#!/bin/bash
global_var=0
func() {
awk '$1 ~/^pattern/ {global_var=$((global_var+1))}' $1
}
func input_file_name
我想在awk操作中增加全局(shell)变量global_var的值。该如何操作?普通的shell样式增加似乎不起作用。
试一下这个:
func() {
awk '$1~/^pattern/ {++awk_var} END {print awk_var+0}' "$1"
}
shell_var=$(func input_file_name)
Shell 和 awk
是独立的世界,你应该将它们视为两个不同的部分(*)(实际上,你已经这样做了,通过将你的 awk
程序放在单引号中,防止 shell 在处理 awk
程序 字符串 时扩展任何Shell变量引用)。
因此,使用 awk
[-内部] 变量来进行计数(awk_var
),并在完成处理输入文件后(在 END
块中),使用 print
输出 awk
变量到 stdout
上(+0
部分是为了确保在找不到匹配项时默认输出为 0
)。
请注意,一般情况下,awk
变量不需要显式初始化,因为它们在数字和布尔上下文中默认为 0
,在字符串上下文中默认为 ""
(空字符串)。
此外,请注意,awk
有自己的语法,像 $((...))
用于算术扩展的 shell 构造不适用于 awk。一般情况下,awk
变量仅仅通过名称进行引用(无需前缀的 $
),并且可以直接应用算术运算,例如 ++
。
使用命令替换 - $(...)
- 在 shell 中允许你捕获 awk
命令的输出。
在你的特定情况下,你不需要将变量值传递给 awk
程序,但如果你需要这样做,你可以使用一个或多个 awk
的 -v
选项; 例如:awk -v awk_var="$shell_var" ...
在 shell(bash
)端,如果你想要将 awk
的输出添加到 shell 变量中而不仅仅是将其赋值给变量:
declare -i shell_var # make sure variable is an integer
shell_var+=$(func input_file_name) # add function's output to existing value
(*) shell 和 awk 有完全独立的命名空间,它们之间没有直接相互作用的方法:awk 没有 shell 变量的概念,而 shell 没有 awk 变量的概念。
将 shell 变量值整合到 awk 程序中是技术上可行但不明智的 - 使用双引号字符串表示 awk 程序,在其中引用 shell 变量值,这些值在字符串被传递给 awk 之前会被 shell 展开一次。
但是不能从 awk 程序内部修改 shell 变量。
由于很快就会变得复杂,无法判断 awk 程序的哪些部分是由 shell 预先解释的,哪些部分是之后由 awk 解释的(例如,'$' 也有特殊含义),所以最佳方法是:
export global_var
,那么你可以从ENVIRON["global_var"]
初始化awk_var
。不是说这是一个好主意,特别是因为它是单向的,但是awk程序至少可以访问环境变量。也许这只会更加混乱而不是有帮助。 - riciawk '$1 ~/^pattern/ {++awk_var} END {print awk_var+0}'
。对于漂亮、详细的解释加一分。 - Ed Morton+0
小技巧 - 已添加到答案中。我使用了 printf
,因为知道结果会被捕获在一个变量中,但我同意这可能会令人困惑(并且通常没有格式字符串不太安全),所以我已经改用了 print
。 - mklement0(( shell_var += $(func input_file_name) ))
。否则awk应该有 -v "awk_var=$shell_var"
。 - konsoleboxawk
中执行的,shell变量只接收结果。我的回答正文确实提到了如何通过-v“awk_var=$shell_var”
传递当前值以演示一般的变量传递。关于您的建议,我认为使用+=
是更清晰的方法——我已经将其添加到答案中,尽管我选择了declare -i
,这样就不必使用((...))
。 - mklement0
awk
命令中,访问变量时不需要使用$
符号。 - WKPlusawk
_程序内部访问_shell_变量(使用_shell_语法,但这是一个次要的问题)。 - mklement0awk
脚本内部访问 shell 变量,而且还在于尝试从awk
脚本内部修改 shell 变量。 - Jonathan Leffler