将 awk 输出用于条件语句

Using awk output for conditional statement

我有一些数据格式如下:

 2     1  500  500  500
 3     1  500  500  500
 6     1  500  500  500
 8     1  500  500  500
 9     1  500  500  500
11     1  500  500  500
12     1  500  500  500
14     1  500  500  500
15     1  500  500  500
16     1  500  500  500
17     1  500  500  500
20     1  500  500  500
21     1  500  500  500
23     1  500  500  500
24     1  500  500  500
25     1  500  500  500
27     1  500  500  500
30     1  500  500  500
31     1  500  500  500
32     1  500  500  500
33     1  500  500  500
34     1  500  500  500
35     1  500  500  500
38     1  500  500  500
40     1  500  500  500
41     1  500  500  500
43     1  500  500  500
44     1  500  500  500
46     1  500  500  500
47     1  500  500  500

我只想将第 1 列等于 11-40 的行中的 500 个值更改为 100。现在我正在做类似的事情:

Numbers=($(seq 11 1 40))
File=filename.txt
for i in ${Numbers[*]}
do
        if [ $i == awk '{print }' $File ];then
        NumberLine=$(grep -n $i $File | cut -d : -f 1)
        sed -i "${NumberLine}s/500/100/" $File
        fi
done

单独来看,每一行似乎都在做我想做的事情,但是当我将它们放入循环中时,出现以下错误:

./changeRestraints.sh: line 5: [: too many arguments

我怀疑这与我的 awk 作为条件语句的一部分有关。我该如何解决这个问题才能制作这个脚本 运行?

谢谢,

为了提高效率,在循环中重复调用 awksed 不是一个好主意。请尝试:

awk '>10 && <=40 {gsub(/\<500\>/, "100")} 1' filename.txt

请注意正则表达式 \<\> 是匹配单词边界的 GNU awk 扩展。

[编辑]
gsub() 函数是 sub() 的变体,它替换了多个 匹配字符串的出现,而 sub() 替换第一个 仅匹配。 sub()gsub() 之间的关系类似于 s/regex/repl/s/regex/repl/gsed.

如果你想为嵌入的数字使用变量,你可以 利用可以分配 awk 变量的 -v varname=value 机制 通过命令行选项:

#!/bin/bash

start=11    # bash variables
stop=40
from=500
to=100
awk -v start="$start" -v stop="$stop" -v from="$from" -v to="$to" '>=start && <=stop {gsub("\<" from "\>", to)} 1' filename.txt
  • 赋值-v start="$start"时,lhsstart是一个awk变量名 rhs "$start" 是一个 bash 变量。我们可以使用相同的名称 他们(尽管他们看起来很混乱)。您还可以分配变量 立即值,例如 -v start=11.
  • 因为我们不能使用正则表达式引用 /regex/ 来包含 awk 变量, 我们需要说 "\<" from "\>" 来代替。中间的空格 只是为了可读性,它等同于 "\<"from"\>".

您从未真正执行过 awk。您将 $i 与字符串 awk 进行比较,然后 test 命令会找到它无法处理的其他参数。因此,您会收到 参数过多 错误。

您需要 运行 awk 才能获得其输出,例如通过执行

if [ "$i" = "$(awk ... )" ]
then
  ...

您也可以使用 sed,其中模式 ^(40|[23][0-9]|1[1-9])[[:space:]] 匹配数字 11-40,后跟字符串开头的 space。

sed -E '/^(40|[23][0-9]|1[1-9])[[:space:]]/s/500/100/g' file

输出

 2     1  500  500  500
 3     1  500  500  500
 6     1  500  500  500
 8     1  500  500  500
 9     1  500  500  500
11     1  100  100  100
12     1  100  100  100
14     1  100  100  100
15     1  100  100  100
16     1  100  100  100
17     1  100  100  100
20     1  100  100  100
21     1  100  100  100
23     1  100  100  100
24     1  100  100  100
25     1  100  100  100
27     1  100  100  100
30     1  100  100  100
31     1  100  100  100
32     1  100  100  100
33     1  100  100  100
34     1  100  100  100
35     1  100  100  100
38     1  100  100  100
40     1  100  100  100
41     1  500  500  500
43     1  500  500  500
44     1  500  500  500
46     1  500  500  500
47     1  500  500  500

gawk 中的另一种方法:

gawk '~/1[1-9]|[23][0-9]|40/{ ===100 }1' file

当您要保留空格时:

gawk '~/1[1-9]|[23][0-9]|40/{ gsub(/\<500\>/,"100") }1' file

使用 sed

sed -i '/^11/,/^40/s/500/100/g' filename.txt

可能是这样的:

mawk 'gsub("500", (_=+)<11 || (40<_) ? "&" : "100")'

 2     1  500  500  500
 3     1  500  500  500
 6     1  500  500  500
 8     1  500  500  500
 9     1  500  500  500
11     1  100  100  100
12     1  100  100  100
14     1  100  100  100
15     1  100  100  100
16     1  100  100  100
17     1  100  100  100
20     1  100  100  100
21     1  100  100  100
23     1  100  100  100
24     1  100  100  100
25     1  100  100  100
27     1  100  100  100
30     1  100  100  100
31     1  100  100  100
32     1  100  100  100
33     1  100  100  100
34     1  100  100  100
35     1  100  100  100
38     1  100  100  100
40     1  100  100  100
41     1  500  500  500
43     1  500  500  500
44     1  500  500  500
46     1  500  500  500
47     1  500  500  500

如果您更喜欢基于 FS + OFS 的方法,那么

 mawk 'NF *= (OFS = (_=+)<11||(40<_) ? FS : __)^!__' FS='500' __='100'