如何使用sed选择特定的行?

  • 本文关键字:何使用 sed 选择 awk sed
  • 更新时间 :
  • 英文 :


在sed的manual中,页面显示了在一个范围内选择特定行的方法。
如何选择没有规则的特定行?

seq 10

例如,如何将第1,3,7行更改为11行?
我尝试使用seq 10 | sed '1s/[0-9]/10/;3s/[0-9]/10/;7s/[0-9]/10/',但这看起来复杂和不清楚。
有没有更简单的方法?

这可能适合您(GNU sed):

printf '%ds/[0-9]/10/n' {1,3,{7..11}} | sed -f - file

将数字序列(通过bash大括号展开)转换为一系列sed命令,并将它们作为stdin传递给使用file作为输入文件的sed调用的文件选项。

或者如OP所愿:

printf '%ds/[0-9]/10/n' {1,3,{7..11}} | sed -f - <(seq 10)

同样的解的另一种写法:

seq 10 | sed $(printf '%ds/[0-9]/10/;' {1,3,{7..11}})

另一种方式:

<<<"1,3,7 to 11" sed -E 's/$/,/;s/,/ba;/g;s/s*(to|-|..)s*([0-9]+)/,2ba;/g;s/;ba//g' |
sed -f - -e 'b;:a;s/[0-9]/10/' <(seq 10)

这可以在awk程序中有效地完成。创建一个名为linesawk变量,并在那里以逗号分隔您想要更改的所有行号。你也可以给出一个范围,例如:7-11 your case,我也在我的程序中使用过。

将您的Input_file传递给该程序,该程序将根据您所显示的尝试将数字替换为10,但这只会在终端上打印输出。一旦您对结果感到满意,然后将 > temp && mv temp Input_file附加到以下代码中,这将执行就地保存到Input_file。

awk -v lines="1,3,7-11" '
BEGIN{
  num=split(lines,arr,",")
  for(i=1;i<=num;i++){
     if(arr[i]~/-/){
        split(arr[i],arr2,"-")
        start=arr2[1]
        while(start<=arr2[2]){
           subArr[start++]
        }
     }
     else{ subArr[arr[i]] }
  }
}
(FNR in subArr){
   sub(/[0-9]/,"10")
}
1' Input_file

如果您的目标是清晰,那么下面的代码是否满足您的要求?

seq 10 | awk '(NR == 1) || (NR == 3) || ((NR >= 7) && (NR <= 11)){gsub(/[0-9]/,"10")} {print}'

直接使用awk:

$ seq 10 | awk '
    BEGIN {
        split("1 3 7",tmp)
        for (i in tmp) {
            tgts[tmp[i]]
        }
    }
    NR in tgts { sub(/[0-9]/, 10) }
    { print }
'
10
2
10
4
5
6
10
8
9
10

或者如果您想包含像其他答案那样指定范围的功能:

$ seq 10 | awk '
    BEGIN {
        split("1 3 7-11", tmp)
        for (i in tmp) {
            n = split(tmp[i], range, /-/)
            for (j=range[1]; j <= range[n]; j++) {
                tgts[j]
            }
        }
    }
    NR in tgts { sub(/[0-9]/, 10) }
    { print }
'
10
2
10
4
5
6
10
10
10
100

如果您愿意使用perl一行代码:

seq 10 | perl -lane 's/[0-9]/10/ if (grep {$_ == $.} (1,3,7..11));print'
10
2
10
4
5
6
10
10
10
100

sed在情况复杂时不适用。
Cyrus在评论中提供的sed解决方案和potong的回答都非常好。

最新更新