有没有办法在我当前的 shell 中设置变量
awk
?
我想对一个文件进行一些处理并打印出一些数据;因为我将通读整个文件,所以我想保存行数 - 在本例中为
FNR
。
虽然我似乎找不到一种方法来设置具有
FNR
值的 shell 变量;如果不是这个,我必须从输出文件中读取 FNR
,以设置 num_lines
,并使用 FNR
值。
我尝试了一些使用
awk 'END{system(...)}'
的组合,但无法使其工作。有什么办法解决这个问题吗?
还有另一种方法。
当您在 single 变量中获得变量的 values 并且想要将它们分开时,这尤其有用。例如,您有数据库中单行的值列表,您希望从中创建变量。
val="hello|beautiful|world" # assume this string comes from a database query
read a b c <<< $( echo ${val} | awk -F"|" '{print $1" "$2" "$3}' )
echo $a #hello
echo $b #beautiful
echo $c #world
我们需要“此处字符串”,即<<< in this case, because the read command does not read from a pipe and instead reads from stdin
$ echo "$var"
$ declare $( awk 'BEGIN{print "var=17"}' )
$ echo "$var"
17
这就是为什么你应该使用declare而不是eval:
$ eval $( awk 'BEGIN{print "echo \"removing all of your files, ha ha ha....\""}' )
removing all of your files, ha ha ha....
$ declare $( awk 'BEGIN{print "echo \"removing all of your files\""}' )
bash: declare: `"removing': not a valid identifier
bash: declare: `files"': not a valid identifier
请注意,在第一种情况下,eval 会执行 awk 打印的任何字符串,这可能会意外地成为一件非常糟糕的事情!
您无法将变量从子 shell 导出到其父 shell。不过,您还有其他一些选择,包括:
使用 AWK 再次遍历该文件来计算记录,并使用命令替换来捕获结果。例如:
FNR=$(awk 'END {print FNR}' filename)
wc -l < filename
来获取您的计数。对任何试图按照几个答案的建议使用声明的人发出警告。
eval没有这个问题。
如果提供的 awk(或其他表达式)声明结果为空字符串,则声明将转储当前环境。 这几乎肯定不是您想要的。
例如:如果你的 awk 模式不存在于输入中,你将永远不会打印输出,因此你最终会出现意想不到的行为。
举个例子......
unset var
var=99
declare $( echo "foobar" | awk '/fail/ {print "var=17"}' )
echo "var=$var"
var=99
The current environment as seen by declare is printed
and $var is not changed
将要设置的值存储在 awk 变量中并在最后打印它的一个小更改解决了这个问题....
unset var
var=99
declare $( echo "foobar" | awk '/fail/ {tmp="17"} END {print "var="tmp}' )
echo "var=$var"
var=
This time $var is unset ie: set to the null string var=''
and there is no unwanted output.
展示其与匹配模式的配合
unset var
var=99
declare $( echo "foobar" | awk '/foo/ {tmp="17"} END {print "var="tmp}' )
echo "var=$var"
var=
This time $var is unset ie: set to the null string var=''
and there is no unwanted output.
使
awk
打印出赋值语句:
MYVAR=NewValue
然后在您的 shell 脚本中,
eval
awk
脚本的输出:
eval $(awk ....)
# then use $MYVAR
编辑:人们建议使用
declare
而不是 eval
,这样如果内部脚本打印作业以外的内容,则更不容易出错。它仅适用于 bash,但是当 shell is bash 并且脚本有 #!/bin/bash
时就可以了,正确地说明了这种依赖关系。
eval $(...)
变体被广泛使用,现有程序生成适合eval
但不适合declare
的输出(lesspipe
是一个例子);这就是为什么理解它很重要,而仅 bash 的变体“过于本地化”。
为了综合到目前为止这里的所有内容,我将分享我发现的从使用 awk 读取单行文件的脚本中设置 shell 环境变量有用的内容。显然可以使用
/pattern/
代替 NR==1
来查找所需的变量。
# export a variable from a script (such as in a .dotfile)
declare $( awk 'NR==1 {tmp=$1} END {print "SHELL_VAR=" tmp}' /path/to/file )
export SHELL_VAR
这将避免在不带参数的情况下发出
declare
命令时大量输出变量,以及盲目eval
的安全风险。
这是 ChatGPT 对这段代码的分析:`
echo "第一个参数:$1" for ((i=0 ; i < $1 ; i++)); do echo "inside" echo "Welcome $i times." cat man.xml | awk '{ x[NR] = $0 } END { for ( i=2 ; i<=NR ; i++ ) { if (x[i] ~ // ) {x[i+1]=" '$i'"}print x[i] }} ' > $i.xml did echo "已完成" `
https://chat.openai.com/share/ae30f6d6-4836-4cd9-8587-ef3e7a655aba
echo“第一个参数:$1” 对于 ((i=0 ; i < $1 ; i++)); do echo "inside" echo "Welcome $i times." cat man.xml | awk '{ x[NR] = $0 } END { for ( i=2 ; i<=NR ; i++ ) { if (x[i] ~ // ) {x[i+1]=" '$i'"}print x[i] }} ' > $i.xml 完毕 回显“已完成”