awk:首先,将一行拆分为单独的行;第二,使用这些新行作为新输入

awk:首先,将一行拆分为单独的行;第二,使用这些新行作为新输入,awk,Awk,假设我有一句话: foo|bar|foobar 我想在|处拆分它,然后使用这3行新行作为进一步程序的输入,比如用xxx替换bar 当然,我可以通过管道传输两个awk实例,如下所示: echo "foo|bar|foobar" | awk '{gsub(/\|/, "\n"); print}' | awk '/bar/ {gsub(/bar/, "xxx"); print}' echo "foo|bar|foobar" | awk -v c=0 '{ {

假设我有一句话:

foo|bar|foobar
我想在|处拆分它,然后使用这3行新行作为进一步程序的输入,比如用xxx替换bar

当然,我可以通过管道传输两个awk实例,如下所示:

echo "foo|bar|foobar" | awk '{gsub(/\|/, "\n"); print}' | awk '/bar/ {gsub(/bar/, "xxx"); print}'
echo "foo|bar|foobar" | awk -v c=0 '{
        {
            gsub(/\|/, "\n");
            sprintf("%s", $0);
        }
        {
            if ($0 ~ /bar/) {
                c+=1;
                gsub(/bar/, "xxx");
                print c;
                print
            }
        }
    }'
但我如何在一个脚本中实现这一点?首先,对某些输入执行一个操作,然后将结果作为第二个操作的新输入

我试过这样的方法:

echo "foo|bar|foobar" | awk '{gsub(/\|/, "\n"); print}' | awk '/bar/ {gsub(/bar/, "xxx"); print}'
echo "foo|bar|foobar" | awk -v c=0 '{
        {
            gsub(/\|/, "\n");
            sprintf("%s", $0);
        }
        {
            if ($0 ~ /bar/) {
                c+=1;
                gsub(/bar/, "xxx");
                print c;
                print
            }
        }
    }'
其结果是:

1
foo
xxx
fooxxx
多亏了计数器c,很明显后续的if不会将它接收到的多行输入视为多条新记录,而是将其视为一条多行记录

因此,我的问题是:如何告诉awk处理这个新的多行记录,它收到的单行记录数量相同

如果我是正确的,本例中的期望输出应该是这样的:

1
xxx
2
fooxxx

但这只是一个例子,问题更多的是关于这种转换的机制。

我建议使用拆分的另一种方法,您可以根据分隔符将元素拆分为一个数组并在其字段上迭代,而不是处理单个多行字符串

echo "foo|bar|foobar" |\
    awk '{
             count = 0
             n = split($0, arr, "|")
             for ( i = 1; i <= n; i++ )
             {
                 if ( arr[i] ~ /bar/ )
                 {
                     count += sub(/bar/, "xxx", arr[i])
                     print count
                     print arr[i]
                 }
             }
         }'

我建议使用split的另一种方法,您可以根据分隔符将元素拆分为一个数组,并在其字段上迭代,而不是处理单个多行字符串

echo "foo|bar|foobar" |\
    awk '{
             count = 0
             n = split($0, arr, "|")
             for ( i = 1; i <= n; i++ )
             {
                 if ( arr[i] ~ /bar/ )
                 {
                     count += sub(/bar/, "xxx", arr[i])
                     print count
                     print arr[i]
                 }
             }
         }'

如果将记录分隔符RS设置为管道字符,则几乎可以获得所需的效果,例如:

echo 'foo|bar|foobar' | awk -v RS='|' 1
输出:

foo
bar
foobar
[...an empty line
除了一个新行字符成为最后一个字段的一部分,因此在输出的末尾有一个额外的行。您可以通过在RS变量中包含一个新行来解决这个问题,使其更不便于移植,或者避免向awk发送新行

例如,使用便携性较差的方式:

echo 'foo|bar|foobar' | awk -v RS='\\||\n' '{ sub(/bar/, "baz") } 1'
输出:

foo
bar
foobar
[...an empty line
福 巴兹 福巴兹
请注意,末尾的空记录将被忽略。

如果将记录分隔符RS设置为管道字符,则几乎可以获得所需的效果,例如:

echo 'foo|bar|foobar' | awk -v RS='|' 1
输出:

foo
bar
foobar
[...an empty line
除了一个新行字符成为最后一个字段的一部分,因此在输出的末尾有一个额外的行。您可以通过在RS变量中包含一个新行来解决这个问题,使其更不便于移植,或者避免向awk发送新行

例如,使用便携性较差的方式:

echo 'foo|bar|foobar' | awk -v RS='\\||\n' '{ sub(/bar/, "baz") } 1'
输出:

foo
bar
foobar
[...an empty line
福 巴兹 福巴兹 请注意,末尾的空记录将被忽略。

使用GNU awk:

$ awk -v RS='[|\n]' 'gsub(/bar/,"xxx"){print ++c ORS $i}' file
1
xxx
2
fooxxx
对于任何awk:

$ awk -F'|' '{c=0; for (i=1;i<=NF;i++) if ( gsub(/bar/,"xxx",$i) ) print ++c ORS $i }' file
1
xxx
2
fooxxx
使用GNU awk:

$ awk -v RS='[|\n]' 'gsub(/bar/,"xxx"){print ++c ORS $i}' file
1
xxx
2
fooxxx
对于任何awk:

$ awk -F'|' '{c=0; for (i=1;i<=NF;i++) if ( gsub(/bar/,"xxx",$i) ) print ++c ORS $i }' file
1
xxx
2
fooxxx

我将仅使用这两个实例。如果用shell而不是awk来描述脚本,那么它有多复杂其实并不重要。好吧,问题不在于如何实现结果,而更像是awk能够解决这个特定任务吗不,AWK没有那个功能。用|分隔字段并循环遍历。我只使用这两个实例。如果用shell而不是awk来描述脚本,那么它有多复杂其实并不重要。好吧,问题不在于如何实现结果,而更像是awk能够解决这个特定任务吗不,AWK没有那个功能。用|分隔字段并循环遍历。