Bash 使用“sed”将代码块中的文本替换为代码块顶部的命令输出
我有一个标记文件,其中包含类似以下示例的代码片段:Bash 使用“sed”将代码块中的文本替换为代码块顶部的命令输出,bash,awk,sed,Bash,Awk,Sed,我有一个标记文件,其中包含类似以下示例的代码片段: ``` $ cat docs/code_sample.sh #!/usr/bin/env bash echo "Hello, world" ``` 这意味着在docs/code\u sample.sh位置有一个文件,其内容是: #!/usr/bin/env bash echo "Hello, world" 我想用sed(awk或perl也可以)解析标记文件,并用上面的bash命令计算的结果替换代码段的底部,例如cat docs/code\
```
$ cat docs/code_sample.sh
#!/usr/bin/env bash
echo "Hello, world"
```
这意味着在docs/code\u sample.sh
位置有一个文件,其内容是:
#!/usr/bin/env bash
echo "Hello, world"
我想用
sed
(awk
或perl
也可以)解析标记文件,并用上面的bash命令计算的结果替换代码段的底部,例如cat docs/code\u sample.sh
计算的结果。perl救命
perl -0777 -pe 's/(?<=```\n)^(\$ (.*)\n\n)(?^s:.*?)(?=```)/"$1".qx($2)/meg' < input > output
perl-0777-pe的/(?perl拯救一切
perl -0777 -pe 's/(?<=```\n)^(\$ (.*)\n\n)(?^s:.*?)(?=```)/"$1".qx($2)/meg' < input > output
perl-0777-pe的/(?如果GNU版本带有e
命令,那么只使用sed的解决方案会更容易
这就是说,这里有一个快速的、简单的、有点笨拙的版本,我删掉了它,它不需要检查前面或后面行的值——它只是假设你的格式是好的,没有任何循环或其他任何东西。但是,对于我的示例代码来说,它仍然有效
我首先制作了一个a
、一个b
、一个x
,这就是标记文件
$: cat a
#! /bin/bash
echo "Hello, World!"
$: cat b
#! /bin/bash
echo "SCREW YOU!!!!"
$: cat x
```
$ cat a
foo
bar
" b a z ! "
```
```
$ cat b
foo
bar
" b a z ! "
```
然后我写了s
,这是sed
脚本
$: cat s
#! /bin/env bash
sed -En '
/^```$/,/^```$/ {
# for the lines starting with the $ prompt
/^[$] / {
# save the command to the hold space
x
# write the ``` header to the pattern space
s/.*/```/
# print the fabricated header
p
# swap the command back in
x
# the next line should be blank - add it to the current pattern space
N
# first print the line of code as-is with the (assumed) following blank line
p
# scrub the $ (prompt) off the command
s/^[$] //
# execute the command - store the output into the pattern space
e
# print the output
p
# put the markdown footer back
s/.*/```/
# and print that
p
}
# for the (to be discarded) existing lines of "content"
/^[^`$]/d
}
' $*
它会起作用,可能会让你开始
$: s x
```
$ cat a
#! /bin/bash
echo "Hello, World!"
```
```
$ cat b
#! /bin/bash
echo "SCREW YOU!!!!"
```
很多警告-最好检查$
后面是否有一行反勾号,后面是否有一行空行,也许可以确保文件中没有任何伪代码可以执行……但这会满足您的要求,使用(GNU)sed
祝您好运。如果您的GNU版本带有e
命令,那么只使用sed的解决方案会更容易
这就是说,这里有一个快速的、简单的、有点笨拙的版本,我删掉了它,它不需要检查前面或后面行的值——它只是假设你的格式是好的,没有任何循环或其他任何东西。但是,对于我的示例代码来说,它仍然有效
我首先制作了一个a
、一个b
、一个x
,这就是标记文件
$: cat a
#! /bin/bash
echo "Hello, World!"
$: cat b
#! /bin/bash
echo "SCREW YOU!!!!"
$: cat x
```
$ cat a
foo
bar
" b a z ! "
```
```
$ cat b
foo
bar
" b a z ! "
```
然后我写了s
,这是sed
脚本
$: cat s
#! /bin/env bash
sed -En '
/^```$/,/^```$/ {
# for the lines starting with the $ prompt
/^[$] / {
# save the command to the hold space
x
# write the ``` header to the pattern space
s/.*/```/
# print the fabricated header
p
# swap the command back in
x
# the next line should be blank - add it to the current pattern space
N
# first print the line of code as-is with the (assumed) following blank line
p
# scrub the $ (prompt) off the command
s/^[$] //
# execute the command - store the output into the pattern space
e
# print the output
p
# put the markdown footer back
s/.*/```/
# and print that
p
}
# for the (to be discarded) existing lines of "content"
/^[^`$]/d
}
' $*
它会起作用,可能会让你开始
$: s x
```
$ cat a
#! /bin/bash
echo "Hello, World!"
```
```
$ cat b
#! /bin/bash
echo "SCREW YOU!!!!"
```
很多警告-最好检查$
后面是否有一行反勾号,后面是否有一行空行,也许可以确保文件中没有任何伪代码可以执行……但这会满足您的要求,使用(GNU)sed
祝你好运。使用getline是一种罕见的情况:
$ cat tst.awk
state == "importing" {
while ( (getline line < $NF) > 0 ) {
print line
}
close($NF)
state = "imported"
}
$0 == "```" { state = (state ? "" : "importing") }
state != "imported" { print }
$ awk -f tst.awk file
$cat tst.awk
状态==“正在导入”{
而((getline<$NF)>0){
打印行
}
收盘价($NF)
state=“已导入”
}
$0==“``{state=(state?”:“importing”)}
状态!=“已导入”{print}
$awk-f tst.awk文件
有关getline的用法和注意事项,请参阅。使用getline非常合适的一种情况:
$ cat tst.awk
state == "importing" {
while ( (getline line < $NF) > 0 ) {
print line
}
close($NF)
state = "imported"
}
$0 == "```" { state = (state ? "" : "importing") }
state != "imported" { print }
$ awk -f tst.awk file
$cat tst.awk
状态==“正在导入”{
而((getline<$NF)>0){
打印行
}
收盘价($NF)
state=“已导入”
}
$0==“``{state=(state?”:“importing”)}
状态!=“已导入”{print}
$awk-f tst.awk文件
有关getline的用法和注意事项,请参阅。因此,始终会有一个3个反勾号的行,后面跟着一个命令,例如带前导的$
的cat docs/code\u sample.sh
,然后是一个空行?您想用第一个命令行的输出替换从第一个空行到最后3个反勾号的所有内容,是吗?@paulhodge是的,这完全正确。因此,始终会有一个3个反勾号行,后面跟着一个命令,例如cat docs/code\u sample.sh
和一个前导的$
,然后是一个空行?您想用第一个命令行的输出替换从第一个空行到最后3个反勾号的所有内容,是吗?@PaulHodges,没错没错。有了所有这些不直观的选项,Perl脚本经常被戏称为“只写”也就不足为奇了@DodgyCodeException:只有三个选项,其中两个相当标准。在生产代码中,我不会使用一行,可能会使用/x
@choroba注释正则表达式。这几乎对我有效,尽管无论何时输入=输出,例如…file.md
,file.md
,wi我将以空结束。如何避免这种情况?输出到另一个文件,然后重命名它。有了所有这些不直观的选项,Perl脚本通常被戏称为“只写”也就不足为奇了@DodgyCodeException:只有三个选项,其中两个相当标准。在生产代码中,我不会使用一行,可能会使用/x
@choroba注释正则表达式。这几乎对我有效,尽管无论何时输入=输出,例如…file.md
,file.md
,wi将以空结尾。如何避免此问题?输出到另一个文件,然后重命名。请注意,它不会进行就地编辑。这会将源文件的备用版本输出到标准输出,以便您重定向到临时文件,在执行其他操作之前,您可以在该临时文件中进行查看。接受解决方案吗?此外,请查看更多有用的详细信息如何实际使用循环,对于一些复杂的示例,尽管它们不太适合这种情况。特别是,本节可能会有所帮助。请注意,它不会进行就地编辑。这将把源文件的备用版本输出到stdout,以便您重定向到临时文件中,在执行任何操作之前,您可以在其中查看它e、 接受解决方案?此外,请查看更多关于如何实际使用循环的有用见解,以及一些复杂的示例,尽管它们不太适合这种情况。特别是,本节可能会有所帮助。