返回不匹配的sed代码

bra*_*ram 51 linux json sed

我正在sed用于在运行时更新我的​​json配置文件.有时,当模式在json文件中不匹配时,仍然sed以退货代码0退出.

返回0表示成功完成,但sed如果找不到正确的模式并更新文件,为什么返回0?有解决方法吗?

谢谢!

Ken*_*ent 51

正如@cnicutar所评论的,命令的返回码意味着命令是否成功执行.与您在代码/脚本中实现的逻辑无关.

所以如果你有:

echo "foo"|sed '/bar/ s/a/b/'
Run Code Online (Sandbox Code Playgroud)

sed会返回0但是如果你写了一些语法/表达式错误,或者输入/文件不存在,sed就无法执行你的请求,sed会返回1.

解决方法

这实际上不是解决方法.sed有q命令:(来自手册页):

 q [exit-code]
Run Code Online (Sandbox Code Playgroud)

在这里,您可以根据需要定义退出代码.例如'/foo/!{q100}; {s/f/b/}',如果foo不存在则退出代码100 ,否则执行替换f-> b并退出代码0.

配对案例:

kent$  echo "foo" | sed  '/foo/!{q100}; {s/f/b/}'
boo
kent$  echo $?
0
Run Code Online (Sandbox Code Playgroud)

无与伦比的案例:

kent$ echo "trash" | sed  '/foo/!{q100}; {s/f/b/}'
trash
kent$ echo $?
100
Run Code Online (Sandbox Code Playgroud)

我希望这回答了你的问题.

编辑

我必须补充一点,上面的例子仅用于单行处理.我不知道你的具体要求.当你想要的时候exit 1.单行不匹配或整个文件.如果整个文件不匹配的情况下,你可以考虑awk,甚至grep在你的文本处理之前做一个...

  • 这个答案非常适合GNU sed,但请注意`q`选项不能移植到BSD(Mac)sed. (6认同)
  • 它也适合单行输入。但是,如果您想要处理文件并想知道是否已完成任何行替换 - 这不是解决方案。有谁知道在这种情况下如何处理? (3认同)
  • @MohammedNoureldin 这在 sed 中确实很常见。像 `seq 20|sed '/7/!d'` 一样阅读手册页。 (2认同)
  • 感谢您提供有用的答案。但是,我不确定您和@cnicutar对返回码的解释。毕竟,当找不到grep模式时,Linux上的`grep`失败,返回码为-1。据我所知,这与sed的retcode哲学不兼容:grep还“尽力而为”以找到(正确指定的)模式,没有错误或缺少输入文件,但是它导致了错误代码,而对于sed来说一切都很好。最后,我们只剩下哪个命令将什么解释为错误,并且没有整体答案... (2认同)
  • 看起来很清楚,最初的请求是找到一种方法让 sed “修改某些行(可能是多行)或告诉我你不能这样做”。如果使用 sed 来修改 stdin,则像“先运行 grep”这样的建议没有用。因此,寻找更通用的解决方案。 (2认同)

pot*_*ong 48

这可能适合你(GNU sed):

sed '/search-string/{s//replacement-string/;h};${x;/./{x;q0};x;q1}' file
Run Code Online (Sandbox Code Playgroud)

如果search-string找到它将被替换为,replacement-string并且在文件结束时sed将退出并0返回代码.如果没有替换发生,则返回代码将是1.

更详细的解释:

在用户中,用户可以使用两个寄存器:当前行加载到的模式空间(PS)(减去换行符)和一个称为保持空间(HS)的备用寄存器,它最初是空的.

一般的想法是使用HS作为标志来指示是否发生了替换.如果HS在文件末尾仍为空,则表示未进行任何更改,否则会发生更改.

该命令/search-string/search-stringPS中的任何内容匹配,如果发现它包含search-string以下大括号之间的命令则执行.

首先是替换s//replacement-string/(sed使用最后一个正则表达式,即search-string如果左侧是空的,那么s//replacement-string它是相同的s/search-string/replacement-string/),然后h命令生成PS的副本并将其放入HS中.

sed命令$用于识别文件的最后一行,然后发生以下行.

首先,x命令交换两个寄存器,因此HS成为PS,PS成为HS.

然后在PS中搜索任何字符/./(.意味着匹配任何字符),记住HS(现在PS)最初是空的,直到替换发生.如果条件为真,x则再次执行,然后执行q0命令,该命令结束所有sed处理并将返回代码设置为0.否则x执行命令并将返回码设置为1.

注意虽然q退出处理它不会阻止PS被sed重新组装并按照正常情况打印.

另一种选择:

sed '/search-string/!ba;s//replacement-string/;h;:a;$!b;p;x;/./Q;Q1' file
Run Code Online (Sandbox Code Playgroud)

要么:

sed '/search-string/,${s//replacement-string/;b};$q1' file
Run Code Online (Sandbox Code Playgroud)


gil*_*ilz 20

这些答案都太复杂了.写一些使用grep的shell脚本来判断你想要替换的东西是否在那里然后使用sed替换它有什么问题?

grep -q $TARGET_STRING $file
if [ $? -eq 0 ]
then
    echo "$file contains the old site"
    sed -e "s|${TARGET_STRING}|${NEW_STRING}|g" ....
fi
Run Code Online (Sandbox Code Playgroud)

  • 如果`$ file`是`/ dev/stdin`,它就不起作用. (2认同)
  • 我喜欢这个,因为当我一个月后回来并忘记我投入学习 sed 语法的两个小时时,我会更容易地将我的代码理解为“做一个简单的字符串替换,看看新字符串是否存在,否则退出” (2认同)

Jen*_*sen 11

对于1 行输入。为了避免重复/模式/:

s替换成功后,使用t来有条件地跳转到某个标签,例如x。否则使用q退出代码退出,例如100

's/pattern/replacement/;tx;q100;:x'

例子:

$ echo 1 > one
$ < one sed 's/1/replaced-it/;tx;q1;:x'
replaced-it
$ echo $?
0
$ < one sed 's/999/replaced-it/;tx;q100;:x'
1
$ echo $?
100
Run Code Online (Sandbox Code Playgroud)

https://www.gnu.org/software/sed/manual/html_node/Branching-and-flow-control.html

  • 从手册页:_“如果省略标签,则分支到脚本末尾”_。看起来像 `s/`...`/`...`/; t; q 128` 更短。 (5认同)
  • 请注意,这使用了 GNU 扩展,这些扩展无法移植到更常规的“sed”变体。 (3认同)