在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
程序中有效地完成。创建一个名为lines
的awk
变量,并在那里以逗号分隔您想要更改的所有行号。你也可以给出一个范围,例如: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的回答都非常好。