我可以使用sed命令中的匹配组,用于生成替换的另一个命令。这样的事情:
sed -e 's/\(<regex>\)/$(<command using \1 reference and generating replacement>)/g'
我需要在第一个文件中替换它,根据另一个文件内容(替换不是常数并基于具体的替换行)。
答案 0 :(得分:2)
正如@EtanReisner所提到的,这只有GNU sed才有可能 - 而且仍然有些棘手。此外,有潜在危险,,只有在输入来自可信赖的来源时才应使用它。
无论如何,e
命令的s///
修饰符在将替换作为shell命令,运行它之后处理模式空间的内容,并用该输出替换模式空间。命令,这意味着必须手动将输出分流到位。一般的模式是
sed '/regex/ { h; s//\n/; x; s//\n&\n/; s/.*\n\(.*\)\n.*/command \1/e; x; G; s/\([^\n]*\)\n\([^\n]*\)\n\(.*\)/\1\3\2/ }' filename
让我们从顶部开始讨论:
/regex/ { # When we find what we seek:
h # Make a copy of the current line in
# the hold buffer.
s//\n/ # Put a newline where the match occurs
# (// reattempts the last attempted
# regex, which is the one from the
# start). This serves as a marker
# where the output of the command will
# be inserted.
x # Swap the copy back in; the marked
# line moves to the hold buffer
s//\n&\n/ # put markers around the match this
# time,
s/.*\n\(.*\)\n.*/command \1/e # then use those markers to construct
# the command and run it. The pattern
# space contains the output of the
# command now.
x # swap the marked line back in
G # append the output to it
s/\([^\n]*\)\n\([^\n]*\)\n\(.*\)/\1\3\2/ # split, reassemble all that in
# the right order, using the
# newline marker we put there in
# the beginning as a splitting
# point.
}
显然, regex
和command
必须替换为你的正则表达式和命令。您可以尝试使用
echo 'foo /tmp/ bar' | sed '/\/\S*/ { h; s//\n/; x; s//\n&\n/; s/.*\n\(.*\)\n.*/ls \1/e; x; G; s/\([^\n]*\)\n\([^\n]*\)\n\(.*\)/\1\3\2/ }'
这将运行ls /tmp/
并将列表放在foo
和bar
之间。
答案 1 :(得分:1)
您可能会发现使用awk更简单,更清晰。例如将输入中间的某个数字乘以3:
$ echo 'abc 12 def' |
awk 'match($0,/[0-9]+/) {print substr($0,1,RSTART-1) substr($0,RSTART,RLENGTH)*3 substr($0,RSTART+RLENGTH)}'
abc 36 def
使用GNU awk,您可以使用第3个arg匹配()来保存正则表达式匹配段:
$ echo 'abc 12 def' |
awk 'match($0,/(.* )([0-9]+)( .*)/,a){print a[1] a[2]*3 a[3]}'
abc 36 def
或将它传递给shell命令(可能不是一个好主意,但可以完成):
$ echo 'abc 12 def' |
awk 'match($0,/(.* )([0-9]+)( .*)/,a){system("echo \"" a[2] "\"")}'
12