![将变量从 FOR 循环传递到 awk 以获取特定单词](https://linux22.com/image/193112/%E5%B0%86%E5%8F%98%E9%87%8F%E4%BB%8E%20FOR%20%E5%BE%AA%E7%8E%AF%E4%BC%A0%E9%80%92%E5%88%B0%20awk%20%E4%BB%A5%E8%8E%B7%E5%8F%96%E7%89%B9%E5%AE%9A%E5%8D%95%E8%AF%8D.png)
我正在尝试以 CSV 格式打印 TXT 文件中表格中的某些单词。
{...some code...}
number_lines=$(awk 'END { print NR }' Table1.txt
if [$number_lines -gt 5]
then
for ((i=5; i<$number_lines; i++))
do
word=$(awk 'FNR==$i {print $2}' Table1.txt)
echo $word
printf "$variable1\t$variable2\t$variable3\t$word\n" >> Table2.csv
done
fi
我以为我可以得到 i $2 行中的单词如果我使用 FNR==5 {print $2} 我会得到我想要的,但是因为我不知道 Table1.txt 中有多少个单词,所以我需要一些东西从第 5 行开始(因为不需要前面的行),直到 Table1.txt -1 行末尾。我希望我糟糕的代码不会让任何人感到不安,我不得不匆忙地做到这一点,并且以前从未在 bash 中做过任何事情,因此很抱歉。
答案1
您可以使用 -v 选项将 shell 变量隐藏到 awk 变量中。
你的 awk 命令看起来像:
awk -v Seq="$i" 'FNR==Seq {print $2}' Table1.txt
提出该修复后,用单个 awk 程序替换所有 10 行会更快,也许更清晰,这将避免读取 Table1 包含的每一行。 awk 非常擅长计算行数和读取数据。
未经测试,但将“某些代码”之后的所有内容替换为以下内容:
awk -v Vars="${variable1}\t${variable2}\t${variable3}\t" \
'FNR >= 5 { printf ("%s\n%s%s\n", $2, Vars, $2); }' \
Table1.txt > Table2.csv
答案2
您不想awk
在这样的循环中重复运行,它将多次读取和处理整个文件(行数 - 4 次)。
理想情况下,最好在 awk (或 perl 或任何非 shell 语言)中完成整个操作,但我不知道你的$variable[123]
变量中有什么或它们是如何定义的(顺便说一句,你可能应该使用如果您要在 bash 中执行此操作,请使用一个数组),所以我将展示如何用 while read 循环替换 for 循环。
while read r word ; do
echo "$word"
printf "$variable1\t$variable2\t$variable3\t$word\n" >> Table2.csv
done < <(awk 'NR > 4 {print $2}')
这仍然不太好(使用 shell 本身进行文本处理从来都不是一个好主意),但至少它只运行awk
一次并且只读取输入文件一次。
答案3
您应该在对 awk 的单次调用中执行此操作,而不是在 shell 循环中重复调用 awk,因为这会非常慢并且很难稳健地编写代码。如果您发布一些简洁的、可测试的示例输入和预期输出,那么我们可以为您提供更多帮助,但听起来这可能就是您想要做的:
awk -v vars="$variable1\t$variable2\t$variable3" '
BEGIN { OFS="\t" }
NR>5 { print vars, prev }
{ prev = $2 }
' Table1.txt > Table2.csv
例如:
$ variable1='this stuff'
$ variable2='other stuff'
$ variable3='last stuff'
$ cat Table1.txt
01 the foo
02 quick bar
03 brown foo
04 fox bar
05 jumped foo
06 over bar
07 the foo
08 lazy bar
09 dogs foo
10 back bar
$ awk -v vars="$variable1\t$variable2\t$variable3" '
BEGIN { OFS="\t" }
NR>5 { print vars, prev }
{ prev = $2 }
' Table1.txt > Table2.csv
$ cat Table2.csv
this stuff other stuff last stuff jumped
this stuff other stuff last stuff over
this stuff other stuff last stuff the
this stuff other stuff last stuff lazy
this stuff other stuff last stuff dogs
如果这些$variable
s 中的任何一个可以包含您不希望扩展的转义序列(例如\t
文本制表符),则执行以下操作:
vars="$variable1"$'\t'"$variable2"$'\t'"$variable3" awk '
BEGIN { vars=ENVIRON["vars"]; OFS="\t" }
NR>5 { print vars, prev }
{ prev = $2 }
' Table1.txt > Table2.csv
看如何在 awk 脚本中使用 shell 变量有关如何将 shell 变量的值传递给 awk 脚本的更多信息。
echo $word
在 shell 脚本中解决这个问题。如果这是一个调试打印,那么它应该真正转到 stderr 而不是 stdout (即它应该写为echo "$word" >&2
),然后你的 awk 脚本将是:
$ awk -v vars="$variable1\t$variable2\t$variable3" '
BEGIN { OFS="\t" }
NR>5 {
print prev | "cat>&2" # or print prev > "/dev/stderr" if your awk supports that
print vars, prev
}
{ prev = $2 }
' Table1.txt > Table2.csv
但如果你真的希望它转到标准输出,那么你可以这样做:
$ awk -v vars="$variable1\t$variable2\t$variable3" '
BEGIN { OFS="\t" }
NR>5 {
print prev
print vars, prev > "Table2.csv"
}
{ prev = $2 }
' Table1.txt
或者:
$ awk -v vars="$variable1\t$variable2\t$variable3" '
BEGIN { OFS="\t" }
NR>5 {
print prev
print vars, prev | "cat>&3"
}
{ prev = $2 }
' Table1.txt 3> "Table2.csv"