【问题标题】:$i doesnt work within the for-loop in an awk statement$i 在 awk 语句的 for 循环中不起作用
【发布时间】:2014-01-18 12:49:04
【问题描述】:

PFB 代码:

for i in 3 4 5 6 7;
do
echo "try $i";
cat vm.txt | cut -f6 -d" " | awk '{ if (NR==$i) print $0 }';
sleep 1;
done;

文件 vm.txt 包含:

 kthr      memory            page            disk          faults      cpu
 r b w   swap  free  re  mf pi po fr de sr s0 s1 s2 s3   in   sy   cs us sy id
 1 0 0 108257664 49651668 401 2616 445 0 0 0 1 3 -0 6 6 1436 13883 1427 1 47 52
 0 0 0 100580908 40823736 1533 4406 4075 1 1 0 0 0 0 0 0 3190 99090 2767 10 2 88
 1 0 0 100580720 40771708 917 5865 0 0 0 0 0 0 0  0  0 3747 137273 3557 13 2 85
 1 0 0 100580168 40721008 401 1725 0 0 0 0 0 0 0  0  0 3220 109486 2761 11 2 87
 1 0 0 100581152 40703900 199 2494 0 0 0 0 0 0 0  0  0 3727 91301 2932 9  2 89
 1 0 0 100581636 40710604 0 0 0 0  0  0  0  0  0  0  0 2472 59069 2136 8  1 91
 1 0 0 100581644 40730952 45 501 0 0 0 0 0  0  0  0  0 2939 87167 2540 9  1 90
 2 0 0 100581632 40712628 46 502 0 0 0 0 0  0  0  0  0 3251 88502 2763 9  1 90
 1 0 0 100581628 40757704 185 219 0 0 0 0 0 0  0  0  0 3058 81429 2590 9  1 90
 1 0 0 100581628 40747620 3602 52322 0 0 0 0 0 0 0 0 0 7353 127233 6077 10 5 85

现在当我运行这个命令时:

cat vm.txt | cut -f6 -d" " | awk '{ if (NR==3) print $0 }';

它可以工作,但在 for 循环中不起作用。我不知道问题是什么。非常感谢您的帮助。

【问题讨论】:

  • 请注意; 字符。在你的命令结束时是多余的;通常,您只需要在命令之间使用; 即可将 multiple 放在 same 行上。
  • 一个与问题无关的建议。具有连续输入数字的 for 循环可以更新为 :for i in {3..7}; do echo $i; done ,因此您无需一一键入数字列表,例如如果超过 100 :)。其次,你的代码一点都不好,需要多次阅读源文件。您应该参考@Ed Morton 的 awk 脚本,该脚本只读取一次。

标签: bash if-statement for-loop awk


【解决方案1】:

awk 的参数用单引号括起来,shell 变量不插在单引号内。您可以将引号更改为双引号(然后将任何确实需要通过 awk 转义的美元符号转义):

for i in 3 4 5 6 7; do
  echo "try $i"
  cat vm.txt | cut -f6 -d" " | awk "{ if (NR==$i) print \$0 }"
  sleep 1
done

或者,使用单引号可能更健壮,但将 shell 变量分配给 Awk 变量(在这个特定示例中没有区别,但一般来说,如果 $i 可能包含空格等... ):

for i in 3 4 5 6 7; do
  echo "try $i"
  cat vm.txt | cut -f6 -d" " | awk -v ndx="$i" '{ if (NR==ndx) print $0 }'
  sleep 1
done

【讨论】:

  • 太棒了,这成功了。起初我试图逃避美元符号,但在单引号中并没有真正做到这一点。非常感激。 :) 谢谢!
  • 绝对不要使用双引号执行上面建议的第一种方法,因为它通过引入转义 $ 符号的需要而使您的 awk 脚本完全不必要地复杂化,并且可能还有其他警告。第二种方法也有问题。一旦我有时间看这个问题,我会发布一些东西。
  • @EdMorton:第二种方法只有一个问题:indexawk 函数的名称,因此不能用作变量名;像ndx 这样的东西就可以了。在风格上,设置变量的 option 形式 - 例如-v ndx="$i" - 之前程序,可能使意图更清晰。
  • @mklement0 感谢您的指点,我已经更新了答案以将它们考虑在内。
  • @EdMorton:这个答案解决了 OP 的直接问题,区分了非功能性和功能性 - 但效率低下; 你的答案在优化方法方面走得更远。因此,您的答案补充这个,并且两者都有价值。如果您的答案是唯一的,那么 OP 对 shell 上下文中的 $awk 上下文中的 $ 的混淆将永远无法消除。
【解决方案2】:

看起来您只想打印第 3 4 5 6 7 行的第 5 个字段。那就是:

$ awk 'NR>=3 && NR<=7{print $5}' vm.txt
49651668
40823736
40771708
40721008
40703900

如果您想要不同的东西,请更新您的问题以澄清。

【讨论】:

  • +1 对原始方法有很大改进(尽管它不会帮助 OP 理解他的问题)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
  • 2021-05-04
  • 2013-12-28
  • 1970-01-01
相关资源
最近更新 更多