在AWK中分配一个Shell变量

3
我有这样的字符串
/home/rm/home-scripts/originals/audicerttest/incoming/TEST040511.txt
/home/rm/home-scripts/originals/audicerttest2/incoming/TEST040512.txt
/home/rm/home-scripts/originals/audicerttest3/incoming/TEST040513.txt

我希望能够将字符串“audicerttest / incoming”,“audicerttest2 / incoming”等提取到shell变量中,并在脚本中稍后使用。 我尝试了以下方法。

for file in `find ${ROOT}/* -type f | grep -v -f test.txt`
do
let count++
echo ${count}: ${file}
echo ${file} | eval $(awk '{split($0,a,"/"); print "abc=a[6]/a[7]"}' < /dev/null)
echo abc====$abc
done

但是它没有输出abc。
5个回答

7

有许多问题,但让我们将问题隔离开来,逐一解决。

给定 - 原始字符串:

/home/rm/home-scripts/originals/audicerttest/incoming/TEST040511.txt

期望的输出 - 你希望将这部分保存在一个变量中:

audicerttest/incoming

如何操作 - 这样做:

string="/home/rm/home-scripts/originals/audicerttest/incoming/TEST040511.txt"
parsed=$(awk 'BEGIN{FS=OFS="/"} {print $6, $7}' <<< ${string})

一般来说,假设你有一个名为 input_file.txt 的文件:

/home/rm/home-scripts/originals/audicerttest/incoming/TEST040511.txt
/home/rm/home-scripts/originals/audicerttest2/incoming/TEST040512.txt
/home/rm/home-scripts/originals/audicerttest3/incoming/TEST040513.txt

您可以做以下事情:

awk 'BEGIN{FS=OFS="/"} {print $6, $7}' input_file.txt > parsed_vars.txt

并且 parsed_vars.txt 将包含:

audicerttest/incoming
audicerttest2/incoming
audicerttest3/incoming

一些解释:

  • parsed=$(...) - 生成子shell并将其输出保存到变量parsed中。
  • awk 'BEGIN{FS=OFS="/"} - 调用awk并将输入和输出的分隔符都设置为/
  • {print $6, $7}' - 根据原始字符串的格式,要打印第六个(audicerttest)和第七个(incoming)字段。
  • <<< ${string} 是使用herestring的表示方法。
  • input_file.txt > parsed_vars.txt - 从指定的输入文件读取,并将输出重定向到一个输出文件。

2
这里提供了一个纯bash的解决方案,不使用任何过度复杂的awk命令,也不使用任何恶意的eval,也不使用任何子shell:
你有这个字符串:
string="/home/rm/home-scripts/originals/audicerttest/incoming/TEST040511.txt"

你需要在变量parsed中包含第5个和第6个字段(分隔符为/)的字符串。让我们开始:
IFS=/ a=( $string ) printf -v parsed '%s/%s' "${a[@]:5:2}"

1
echo ${file} | eval $(awk '{split($0,a,"/"); print "abc=a[6]/a[7]"}' < /dev/null)

好的,这里有几个问题。

awk 正在从 /dev/null 读取,这没有任何意义,我猜你想处理文件名:

echo {$file} | awk ... 

"a[6]" 是字符串 a[6],不进行任何替换。

现在对整个表达式进行求值:

eval $(echo $file | awk '{split($0,a,"/"); print "abc="a[6]"/"a[7]""}')

最后,eval是有害的,为什么不直接设置变量呢?
abc=$(echo $file | awk '{split($0,a,"/"); print a[6]"/"a[7]}')

就个人而言,我认为这更加清晰明了:

 cut -d / --output-delimiter / -f6,7

你的方法中主要问题是无用地使用了 evaleval 是邪恶的!更不用说无用的子 shell 了。 - gniourf_gniourf
我只是在更新我的回答...他正在使用一种效率低下的工具来完成任务,但(我希望)他是在询问为什么它不起作用,而不仅仅是寻求另一个解决方案。所以,不知道为什么会被踩。 - Karoly Horvath
我是Shell的新手,我同意有太多的错误。感谢您对这些错误的纠正。 - Ravi

1

只使用bash数组,您可以执行以下操作:

假设:

path=/home/rm/home-scripts/originals/audicerttest/incoming/TEST040511.txt

然后:

IFS=/ split=(${path})
path_part="${split[5]}/${split[6]}"

$split 将是一个数组,其中元素 0 为空,元素一为 home,元素二为 rm 等等。有了这个,你只需要连接你想要的元素,就可以得到你喜欢的部分。


0

没有人建议使用简单的参数扩展来操作字符串。我假设前4个目录是不变的。

while read path; do
    dirname=$(dirname $path)
    abc=${dirname#/home/rm/home-scripts/originals/}
    echo "abc===$abc"
done < filename

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接