将变量从 FOR 循环传递到 awk 以获取特定单词

将变量从 FOR 循环传递到 awk 以获取特定单词

我正在尝试以 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

如果这些$variables 中的任何一个可以包含您不希望扩展的转义序列(例如\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"

相关内容