Awk:将传递的 Bash 变量与列值进行比较

Awk:将传递的 Bash 变量与列值进行比较

使用这个例子:

#submission,date
"test1","22 April 2024"
"test2","24 April 2024"
"test3","25 March 2024"
"test6","01 April 2023"
"test7","02 April 2022"
"test8","03 April 2021"

我只想打印当月的测试,截至撰写本文时是 2024 年 4 月。尝试以下命令:

awk -F, -v date="$(date +'%B %Y')" '/^[^#]/ && $2 ~ /'$date'\"$/{print $1}' tests.csv

打印所有测试。如何使用 Awk 比较 Bash 变量?

答案1

关于How are variables ...- 非常清楚你的思维、代码和问题中“变量”的含义。您正在从 shell、bash 调用 awk。 Bash 不是 awk - 它们是两个完全独立的工具,每个工具都有自己的语法、语义、范围和变量

在你的代码中你有:

awk -v date="$(date +'%B %Y')"

正在填充一个awk 变量,不是 shell 变量,包含对其他 Unix 工具的调用的输出date

就像在 awk 中一样C,在 awk 中,您只需使用变量的名称即可获取变量的值,而在 shell 中,您必须$在变量名称前面放置 a 才能获取其值,因此在代码的下一部分中:

$2 ~ /'$date'\"$/

你只需要使用它date来获取 awk 变量的值date,但是现在你有第二个问题 - 你在里面使用它文字正则表达式分隔符/.../,但您需要从变量date加上字符串来构造正则表达式\"$,因此您需要一个动态正则表达式那里,不是字面的正则表达式。鉴于此,您的代码的该部分应该是:

$2 ~ (date "\"$")

鉴于此,您的脚本将是:

$ awk -F, -v date="$(date +'%B %Y')" '/^[^#]/ && $2 ~ (date "\"$"){print $1}' tests.csv
"test1"
"test2"

date不过,如果是我,那么我会在第一次初始化时进行串联以形成正则表达式:

awk -F, -v date="$(date +'%B %Y')\"$" '/^[^#]/ && $2 ~ date{print $1}'

或在以下BEGIN部分:

awk -F, -v date="$(date +'%B %Y')" 'BEGIN{date=date "\"$"} /^[^#]/ && $2 ~ (date "\"$"){print $1}'

因此每个输入行不会发生一次,因为字符串连接是一个相对较慢的操作。

如果您有 GNU awk,另一个选择是存储强类型正则表达式常量而不是变量中的动态正则表达式字符串date

awk -F, -v date="@/$(date +'%B %Y')[^\"]+\"$/" '/^[^#]/ && $2 ~ date{print $1}' file

或者:

awk -F, -v d="$(date +'%B %Y')" 'BEGIN{date=@/x[^"]+"$/; sub(/x/,d,date)} /^[^#]/ && $2 ~ date{print $1}' file

但第二个变得相当神秘,一个普通的旧动态正则表达式在您的特定情况下工作得很好。

如果您确实想在 awk 脚本中使用 shell 变量的值,请参阅如何在 awk 脚本中使用 shell 变量如何做到这一点。

相关内容