Bash 查找正则表达式模式,将该模式传递给脚本,并用脚本的输出替换该模式
每当模式出现时(在本例中为2位数字),我都希望将该模式传递给脚本,并用脚本的输出替换该模式 我用sed作为例子,说明它应该是什么样子Bash 查找正则表达式模式,将该模式传递给脚本,并用脚本的输出替换该模式,bash,sed,scripting,Bash,Sed,Scripting,每当模式出现时(在本例中为2位数字),我都希望将该模式传递给脚本,并用脚本的输出替换该模式 我用sed作为例子,说明它应该是什么样子 echo 'siedi87sik65owk55dkd' | sed 's/[0-9][0-9]/.\/script.sh/g' 现在它回来了 siedi./script.shsik./script.showk./script.shdkd 但我希望它能回来 siedi!!!87!!!sik!!!65!!!owk!!!55!!!dkd 这就是./script.s
echo 'siedi87sik65owk55dkd' | sed 's/[0-9][0-9]/.\/script.sh/g'
现在它回来了
siedi./script.shsik./script.showk./script.shdkd
但我希望它能回来
siedi!!!87!!!sik!!!65!!!owk!!!55!!!dkd
这就是./script.sh中的内容
#!/bin/bash
echo "!!!$1!!!"
必须用输出替换它。在这个例子中,我知道我可以使用一个普通的sed替换,但我不想把它作为一个答案。sed只用于单个行上的简单替换,仅此而已。其他任何事情,即使可以做到,都需要神秘的语言结构,这种结构在20世纪70年代中期awk发明时就已经过时,今天纯粹是用于心理训练。您的问题不是简单的替换,因此您不应该尝试使用sed来解决它 您将需要以下内容:
awk '{
head = ""
tail = $0
while ( match(tail,/[0-9]{2}/) ) {
tgt = substr(tail,RSTART,RLENGTH)
cmd = "./script.sh " tgt
if ( (cmd | getline line) > 0) {
tgt = line
}
close(cmd)
head = head substr(tail,1,RSTART-1) tgt
tail = substr(tail,RSTART+RLENGTH)
}
print head tail
}'
e、 g.使用echo
代替script.sh
命令:
$ echo 'siedi87sik65owk55dkd' |
awk '{
head = ""
tail = $0
while ( match(tail,/[0-9]{2}/) ) {
tgt = substr(tail,RSTART,RLENGTH)
cmd = "echo !!!" tgt "!!!"
if ( (cmd | getline line) > 0) {
tgt = line
}
close(cmd)
head = head substr(tail,1,RSTART-1) tgt
tail = substr(tail,RSTART+RLENGTH)
}
print head tail
}'
siedi!!!87!!!sik!!!65!!!owk!!!55!!!dkd
sed是对单个行的简单替换,仅此而已。其他任何事情,即使可以做到,都需要神秘的语言结构,这种结构在20世纪70年代中期awk发明时就已经过时,今天纯粹是用于心理训练。您的问题不是简单的替换,因此您不应该尝试使用sed来解决它 您将需要以下内容:
awk '{
head = ""
tail = $0
while ( match(tail,/[0-9]{2}/) ) {
tgt = substr(tail,RSTART,RLENGTH)
cmd = "./script.sh " tgt
if ( (cmd | getline line) > 0) {
tgt = line
}
close(cmd)
head = head substr(tail,1,RSTART-1) tgt
tail = substr(tail,RSTART+RLENGTH)
}
print head tail
}'
e、 g.使用echo
代替script.sh
命令:
$ echo 'siedi87sik65owk55dkd' |
awk '{
head = ""
tail = $0
while ( match(tail,/[0-9]{2}/) ) {
tgt = substr(tail,RSTART,RLENGTH)
cmd = "echo !!!" tgt "!!!"
if ( (cmd | getline line) > 0) {
tgt = line
}
close(cmd)
head = head substr(tail,1,RSTART-1) tgt
tail = substr(tail,RSTART+RLENGTH)
}
print head tail
}'
siedi!!!87!!!sik!!!65!!!owk!!!55!!!dkd
Ed's显然是一个不错的选择
为了好玩,我尝试提出一个sed解决方案,这里是一个(复杂的gnused)解决方案,它将运行的模式和脚本作为参数;输入可以从标准输入读取(即,可以通过管道读取),也可以从作为第三个参数提供的文件读取
例如,我们将用内容填充infle
siedi87sik65owk55dkd
siedi11sik22owk33dkd
#!/bin/bash
echo "!!!${1}!!!"
(用两行代码演示如何在多行代码中使用),然后使用内容
siedi87sik65owk55dkd
siedi11sik22owk33dkd
#!/bin/bash
echo "!!!${1}!!!"
最后是解决方案脚本本身,so
。用法是
./so pattern script [input]
或者,作为过滤器
cat infile | ./so '[[:digit:]]{2}' script
有输出
siedi!!!87!!!sik!!!65!!!owk!!!55!!!dkd
siedi!!!11!!!sik!!!22!!!owk!!!33!!!dkd
这就是的样子
:
#!/bin/bash
pat=$1 # The pattern to match
script=$2 # The command to run for each pattern
infile=${3:-/dev/stdin} # Read from standard input if not supplied
# Use sed and have $pattern and $script expand to the supplied parameters
sed -r "
:build_loop # Label to loop back to
h # Copy pattern space to hold space
s/.*($pat).*/.\/\"$script\" \1/ # (1) Extract last match and prepare command
# Replace pattern space with output of command
e
G # (2) Append hold space to pattern space
s/(.*)$pat(.*)/\1~~~\2/ # (3) Replace last match of pattern with ~~~
/\n[^\n]*$pat[^\n]*$/b build_loop # Loop if string contains match
:fill_loop # Label for second loop
s/(.*\n)(.*)\n([^\n]*)~~~([^\n]*)$/\1\3\2\4/ # (4) Replace last ~~~
t fill_loop # Loop if there was a replacement
s/(.*)\n(.*)~~~(.*)$/\2\1\3/ # (5) Final ~~~ replacement
" < "$infile"
然后,e
命令(GNU扩展)用该命令的输出替换模式空间。在此之后,G
将保持空间附加到图案空间(2)。图案空间现在如下所示:
./script 55
!!!55!!!
siedi87sik65owk55dkd
!!!87!!!
!!!65!!!
!!!55!!!
siedi~~~sik~~~owk~~~dkd
(3)处的替换将最后一个匹配替换为一个字符串,希望该字符串不等于模式,我们得到
!!!55!!!
siedi87sik65owk~~~dkd
如果模式空间的最后一行仍然与模式匹配,则循环将重复。经过三次循环后,图案空间如下所示:
./script 55
!!!55!!!
siedi87sik65owk55dkd
!!!87!!!
!!!65!!!
!!!55!!!
siedi~~~sik~~~owk~~~dkd
现在,第二个循环将模式空间的最后一行替换为替换(4)。该命令使用了大量的“非换行符”([^\n]
)来确保我们没有为~~
进行错误的替换
由于命令(4)的编写方式,循环以最后一次替换结束,因此在命令(5)之前,我们有以下模式空间:
!!!87!!!
siedi~~~sik!!!65!!!owk!!!55!!!dkd
命令(5)是命令(4)的一个更简单版本,在它之后,输出是所需的
这似乎相当健壮,可以处理要运行的脚本名称中的空格,只要在调用时正确引用:
./so '[[:digit:]]{2}' 'my script' infile
如果
- 输入文件包含
(可通过替换开头的所有引用,将它们放回末尾来解决)~~
脚本的输出包含
~~
- 模式包含
~~
~
的唯一性
因为没有人问:
so
作为一行
#/bin/bash
sed-re:b;h;s/*($1)。*/.\/\“$2\”\1/;e“-e”G;s/(.*)$1(.*)/\1~~~\2/;/\n[^\n]*$1[^\n]*$/bb;:f;s/(.\n)(.*)\n([^\n]*)~([^\n]*)$/\1\3\2\4/;“$tf
仍然有效 Ed's显然是一个不错的选择
为了好玩,我尝试提出一个sed解决方案,这里是一个(复杂的gnused)解决方案,它将运行的模式和脚本作为参数;输入可以从标准输入读取(即,可以通过管道读取),也可以从作为第三个参数提供的文件读取
例如,我们将用内容填充infle
siedi87sik65owk55dkd
siedi11sik22owk33dkd
#!/bin/bash
echo "!!!${1}!!!"
(用两行代码演示如何在多行代码中使用),然后使用内容
siedi87sik65owk55dkd
siedi11sik22owk33dkd
#!/bin/bash
echo "!!!${1}!!!"
最后是解决方案脚本本身,so
。用法是
./so pattern script [input]
或者,作为过滤器
cat infile | ./so '[[:digit:]]{2}' script
有输出
siedi!!!87!!!sik!!!65!!!owk!!!55!!!dkd
siedi!!!11!!!sik!!!22!!!owk!!!33!!!dkd
这就是的样子
:
#!/bin/bash
pat=$1 # The pattern to match
script=$2 # The command to run for each pattern
infile=${3:-/dev/stdin} # Read from standard input if not supplied
# Use sed and have $pattern and $script expand to the supplied parameters
sed -r "
:build_loop # Label to loop back to
h # Copy pattern space to hold space
s/.*($pat).*/.\/\"$script\" \1/ # (1) Extract last match and prepare command
# Replace pattern space with output of command
e
G # (2) Append hold space to pattern space
s/(.*)$pat(.*)/\1~~~\2/ # (3) Replace last match of pattern with ~~~
/\n[^\n]*$pat[^\n]*$/b build_loop # Loop if string contains match
:fill_loop # Label for second loop
s/(.*\n)(.*)\n([^\n]*)~~~([^\n]*)$/\1\3\2\4/ # (4) Replace last ~~~
t fill_loop # Loop if there was a replacement
s/(.*)\n(.*)~~~(.*)$/\2\1\3/ # (5) Final ~~~ replacement
" < "$infile"
然后,e
命令(GNU扩展)用该命令的输出替换模式空间。在此之后,G
将保持空间附加到图案空间(2)。图案空间现在如下所示:
./script 55
!!!55!!!
siedi87sik65owk55dkd
!!!87!!!
!!!65!!!
!!!55!!!
siedi~~~sik~~~owk~~~dkd
(3)处的替换将最后一个匹配替换为一个字符串,希望该字符串不等于模式,我们得到
!!!55!!!
siedi87sik65owk~~~dkd
如果模式空间的最后一行仍然与模式匹配,则循环将重复。经过三次循环后,图案空间如下所示:
./script 55
!!!55!!!
siedi87sik65owk55dkd
!!!87!!!
!!!65!!!
!!!55!!!
siedi~~~sik~~~owk~~~dkd
现在,第二个循环将模式空间的最后一行替换为替换(4)。该命令使用了大量的“非换行符”([^\n]
)来确保我们没有为~~
进行错误的替换
由于命令(4)的编写方式,循环以最后一次替换结束,因此在命令(5)之前,我们有以下模式空间:
!!!87!!!
siedi~~~sik!!!65!!!owk!!!55!!!dkd
命令(5)是命令(4)的一个更简单版本,在它之后,输出是所需的
这似乎相当健壮,可以处理要运行的脚本名称中的空格,只要在调用时正确引用:
./so '[[:digit:]]{2}' 'my script' infile
如果
- 输入文件包含
(可通过替换所有~~