使用 sed 将字符串模式替换为序列

使用 sed 将字符串模式替换为序列

我想用数字序列替换文本文件中的字符串,例如 1 2 3 4 5 6 7 最好使用 sed。

这是我尝试过的(没有搜索字符串)并且似乎有效:

for i in {1..5};do echo $(seq 1 $i); done

输出:

1
1 2
1 2 3
1 2 3 4
1 2 3 4 5

但是,当我尝试这样做时:

for i in {1..5};do sed -i "s/abc/$(seq 1 $i)/g" test; done

我收到以下错误:

sed: -e expression #1, char 8: unterminated `s' command
sed: -e expression #1, char 8: unterminated `s' command
sed: -e expression #1, char 8: unterminated `s' command
sed: -e expression #1, char 8: unterminated `s' command

我也尝试过将替换字符串括在括号中,但似乎不起作用。

第一个循环

for i in {1..5}

将被替换为文件名的 glob,我想在其中替换一些参数。

答案1

TL;博士:

有一些方法可以解决这个问题,我认为最适合您的示例案例的是:

for i in {1..5};do sed -i "s/abc/$(seq -s ' ' 1 $i)/g" test; done

即:我们要求seq用一个空格来分隔每个数字。

解释:

您收到这些错误的原因是因为输出:

seq 1 5

不是:

1 2 3 4 5

反而:

1
2
3
4
5

既然你附上了$(seq 1 $i) 命令替换双引号内,通常分词不执行,因此实用程序输出的所有换行符(最后一个除外)seq都保留原样。

因此实际的sed 命令变成了:

sed -i "s/abc/1
2
3
4
5
/g" test

这是不被接受的,因为就目前而言sed ,您向它提供了一个s/abc/1命令,即缺少所需的 Final /

Anecho $(seq 1 5)确实会打印,1 2 3 4 5因为$(seq 1 5)不在双引号内,因此按照 shell 的默认行为发生分词。

我们确实可以修复您的示例案例,如下所示:

for i in {1..5};do sed -i "s/abc/$(echo $(seq 1 $i))/g" test; done

也就是说,通过执行命令替换(您原来的seq 1 $i里面另一个命令替换(echo一个)。

即使在双引号内,这也有效,因为$(echo ...)命令替换是在子外壳这是不是处于“I-am-inside-a-double-quote”状态,因此对输出进行分词seq 将要在那里进行。

答案2

您可以将输出通过管道传输到临时文件,然后将临时文件移至原始文件之上。还有,你可能本来打算一次只操作一行,在这种情况下,您应该删除g

for i in {1..5}; do
    sed -e "s/abc/$(seq 1 $i)/" test > test.tmp
    mv test.tmp test
done

相关内容