循环更改列 - 如何不用$ i错误列的$

时间:2021-09-21 16:06:43

I would like to make a loop for change columns in a awk condition. However, the $ symbol is making mistake with the replacement for "i". Any idea how to fix it?

我想在awk条件下为更改列创建一个循环。但是,$符号在替换“i”时出错。知道怎么解决吗?

#!/bin/bash
for i in {2..5}
do
awk '$$i>=10 && $$i<=20' permut1.txt >> out.txt
done

input:

输入:

abc 1 1 2 3 4
bbb 0 1 2 0 1
ccc 1 1 0 2 2
ddd 0 1 3 1 3
fff 15 15 4 15 15
ggg 15 15 15 15 15

I want this output:

我想要这个输出:

ggg 15 15 15 15 15

1 个解决方案

#1


2  

In awk, $ is a prefix operator whose argument must be a non-negative integer. That's quite different from the meaning of the $ in bash.

在awk中,$是一个前缀运算符,其参数必须是非负整数。这与bash中$的含义完全不同。

The easiest way to pass a variable from bash to awk is to use the -v var=value command line option in the awk command:

将变量从bash传递到awk的最简单方法是在awk命令中使用-v var = value命令行选项:

awk -v field=2 '$field >= 10 && $field <= 20' permut1.txt

The above will print all lines whose second field is between 10 and 20. You could iterate in bash to do multiple scans of the data, each one scanning a different column:

上面将打印第二个字段在10到20之间的所有行。您可以在bash中迭代以对数据进行多次扫描,每次扫描不同的列:

for i in 2 3 4; do
  awk -v field=$i '$field >= 10 && $field <= 20' permut1.txt
done

But I suspect that what you are trying to do is to iterate in awk over the fields, and print the lines which satisfy all three tests. Again, the fact that the awk $ is an operator can make this relatively simple. Another awk feature which simplifies the logic is the next command, which reads the next input line and restarts the pattern matching loop. That makes it easy to require that all three tests match:

但我怀疑你要做的是在字段上进行awk迭代,并打印满足所有三个测试的行。同样,awk $是一个运算符的事实可以使这相对简单。另一个简化逻辑的awk功能是下一个命令,它读取下一个输入行并重新启动模式匹配循环。这使得要求所有三个测试都匹配很容易:

awk '{ for (field = 2; field < 5; ++field) {
         if ($field < 10 || $field > 20) next;
       }
       # We can only get here if none of the fields were outside
       # the range. $0 is the entire line.
       print $0;
     }' permut1.txt

Because the default pattern action is precisely print $0, we can shorten that script:

因为默认模式操作正好打印$ 0,所以我们可以缩短该脚本:

awk '{ for (field = 2; field < 5; ++field) 
         if ($field < 10 || $field > 20) next;
       }
     } 1' permut1.txt

The 1 at the end is a condition which will always be true, with no action (or, in other words, the default action); if the preceding rule doesn't execute the next command for any of the fields, then the 1 condition will be executed, and the default action will cause the line to be printed.

最后的1是一个始终为真的条件,没有任何动作(换句话说,默认动作);如果前面的规则没有为任何字段执行下一个命令,那么将执行1条件,默认操作将导致打印该行。

#1


2  

In awk, $ is a prefix operator whose argument must be a non-negative integer. That's quite different from the meaning of the $ in bash.

在awk中,$是一个前缀运算符,其参数必须是非负整数。这与bash中$的含义完全不同。

The easiest way to pass a variable from bash to awk is to use the -v var=value command line option in the awk command:

将变量从bash传递到awk的最简单方法是在awk命令中使用-v var = value命令行选项:

awk -v field=2 '$field >= 10 && $field <= 20' permut1.txt

The above will print all lines whose second field is between 10 and 20. You could iterate in bash to do multiple scans of the data, each one scanning a different column:

上面将打印第二个字段在10到20之间的所有行。您可以在bash中迭代以对数据进行多次扫描,每次扫描不同的列:

for i in 2 3 4; do
  awk -v field=$i '$field >= 10 && $field <= 20' permut1.txt
done

But I suspect that what you are trying to do is to iterate in awk over the fields, and print the lines which satisfy all three tests. Again, the fact that the awk $ is an operator can make this relatively simple. Another awk feature which simplifies the logic is the next command, which reads the next input line and restarts the pattern matching loop. That makes it easy to require that all three tests match:

但我怀疑你要做的是在字段上进行awk迭代,并打印满足所有三个测试的行。同样,awk $是一个运算符的事实可以使这相对简单。另一个简化逻辑的awk功能是下一个命令,它读取下一个输入行并重新启动模式匹配循环。这使得要求所有三个测试都匹配很容易:

awk '{ for (field = 2; field < 5; ++field) {
         if ($field < 10 || $field > 20) next;
       }
       # We can only get here if none of the fields were outside
       # the range. $0 is the entire line.
       print $0;
     }' permut1.txt

Because the default pattern action is precisely print $0, we can shorten that script:

因为默认模式操作正好打印$ 0,所以我们可以缩短该脚本:

awk '{ for (field = 2; field < 5; ++field) 
         if ($field < 10 || $field > 20) next;
       }
     } 1' permut1.txt

The 1 at the end is a condition which will always be true, with no action (or, in other words, the default action); if the preceding rule doesn't execute the next command for any of the fields, then the 1 condition will be executed, and the default action will cause the line to be printed.

最后的1是一个始终为真的条件,没有任何动作(换句话说,默认动作);如果前面的规则没有为任何字段执行下一个命令,那么将执行1条件,默认操作将导致打印该行。