从 awk 在当前 shell 中设置变量

问题描述 投票:0回答:8

有没有办法在我当前的 shell 中设置变量

awk

我想对一个文件进行一些处理并打印出一些数据;因为我将通读整个文件,所以我想保存行数 - 在本例中为

FNR

虽然我似乎找不到一种方法来设置具有

FNR
值的 shell 变量;如果不是这个,我必须从输出文件中读取
FNR
,以设置
num_lines
,并使用
FNR
值。

我尝试了一些使用

awk 'END{system(...)}'
的组合,但无法使其工作。有什么办法解决这个问题吗?

bash variables awk
8个回答
40
投票

还有另一种方法。

当您在 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


31
投票
$ 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 打印的任何字符串,这可能会意外地成为一件非常糟糕的事情!


7
投票

您无法将变量从子 shell 导出到其父 shell。不过,您还有其他一些选择,包括:

  1. 使用 AWK 再次遍历该文件来计算记录,并使用命令替换来捕获结果。例如:

    FNR=$(awk 'END {print FNR}' filename)
    
  2. 在子 shell 中打印 FNR,并在其他进程中解析输出。
  3. 如果FNR与行数相同,您可以拨打
    wc -l < filename
    来获取您的计数。

4
投票

对任何试图按照几个答案的建议使用声明的人发出警告。

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.

1
投票

使

awk
打印出赋值语句:

MYVAR=NewValue

然后在您的 shell 脚本中,

eval
awk
脚本的输出:

eval $(awk ....)
# then use $MYVAR

编辑:人们建议使用

declare
而不是
eval
,这样如果内部脚本打印作业以外的内容,则更不容易出错。它仅适用于 bash,但是当 shell is bash 并且脚本有
#!/bin/bash
时就可以了,正确地说明了这种依赖关系。

eval $(...)
变体被广泛使用,现有程序生成适合
eval
但不适合
declare
的输出(
lesspipe
是一个例子);这就是为什么理解它很重要,而仅 bash 的变体“过于本地化”。


1
投票

为了综合到目前为止这里的所有内容,我将分享我发现的从使用 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
的安全风险。


0
投票

这是 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


-1
投票

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 完毕 回显“已完成”

© www.soinside.com 2019 - 2024. All rights reserved.