Linux 不匹配时 sed 的返回码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15965073/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 22:41:43  来源:igfitidea点击:

Return code of sed for no match

linuxjsonsed

提问by bram

I'm using sedfor updating my json configuration file in the runtime. Sometimes, when the pattern doesn't matches in the json file, still sedexits with return code 0.

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

Returning 0 means successful completion, but why does sedreturns 0 if it doesnt find the proper pattern and update the file? Is there a workaround for that?

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

Thanks!

谢谢!

采纳答案by Kent

as @cnicutar commented, the return code of a command means if the command was executed successfully. has nothing to do with the logic you implemented in the codes/scripts.

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

so if you have:

所以如果你有:

echo "foo"|sed '/bar/ s/a/b/'

sed will return 0but if you write some syntax/expression errors, or the input/file doesn't exist, sed cannot execute your request, sed will return 1.

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

workaround

解决方法

this is actually not workaround. sed has qcommand: (from man page):

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

 q [exit-code]

here you can define exit-code as you want. For example '/foo/!{q100}; {s/f/b/}'will exit with code 100 if fooisn't present, and otherwise perform the substitution f->b and exit with code 0.

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

Matched case:

匹配案例:

kent$  echo "foo" | sed  '/foo/!{q100}; {s/f/b/}'
boo
kent$  echo $?
0

Unmatched case:

无与伦比的案例:

kent$ echo "trash" | sed  '/foo/!{q100}; {s/f/b/}'
trash
kent$ echo $?
100

I hope this answers your question.

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

edit

编辑

I must add that, the above example is just for one-line processing. I don't know your exact requirement. when you want to get exit 1. one-line unmatched or the whole file. If whole file unmatching case, you may consider awk, or even do a grepbefore your text processing...

我必须补充一点,上面的示例仅用于单行处理。我不知道你的确切要求。当你想得到exit 1. 一行不匹配或整个文件。如果整个文件不匹配,您可以考虑使用 awk,甚至grep在您的文本处理之前做一个...

回答by potong

This might work for you (GNU sed):

这可能对你有用(GNU sed):

sed '/search-string/{s//replacement-string/;h};${x;/./{x;q0};x;q1}' file

If the search-stringis found it will be replaced with replacement-stringand at end-of-file sedwill exit with 0return code. If no substitution takes place the return code will be 1.

如果search-string找到,它将被替换,replacement-string并且在文件末尾sed将退出并0返回代码。如果没有发生替换,返回码将为1

A more detailed explanation:

更详细的解释:

In sed the user has two registers at his disposal: the pattern space (PS) in which the current line is loaded into (minus the linefeed) and a spare register called the hold space (HS) which is initially empty.

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

The general idea is to use the HS as a flag to indicate if a substitution has taken place. If the HS is still empty at the end of the file, then no changes have been made, otherwise changes have occurred.

一般的想法是使用 HS 作为标志来指示是否发生了替换。如果文件末尾的 HS 仍然是空的,则没有进行任何更改,否则已发生更改。

The command /search-string/matches search-stringwith whatever is in the PS and if it is found to contain the search-stringthe commands between the following curly braces are executed.

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

Firstly the substitution s//replacement-string/(sed uses the last regexp i.e. the search-string, if the lefthand-side is empty, so s//replacement-stringis the same as s/search-string/replacement-string/) and following this the hcommand makes a copy of the PS and puts it in the HS.

首先进行替换s//replacement-string/(sed 使用最后一个正则表达式,即search-string,如果左侧为空,s//replacement-string则与 相同s/search-string/replacement-string/),然后h命令制作 PS 的副本并将其放入 HS。

The sed command $is used to recognise the last line of a file and the following then occurs.

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

First the xcommand swaps the two registers, so the HS becomes the PS and the PS becomes the HS.

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

Then the PS is searched for any character /./(.means match any character) remember the HS (now the PS) was initially empty until a substitution took place. If the condition is true the xis again executed followed by q0command which ends all sed processing and sets the return code to 0. Otherwise the xcommand is executed and the return code is set to 1.

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

N.B. although the qquits sed processing it does not prevent the PS from being reassembled by sed and printed as per normal.

注意,虽然q退出 sed 处理,但它不会阻止 PS 被 sed 重新组装并按正常方式打印。

Another alternative:

另一种选择:

sed '/search-string/!ba;s//replacement-string/;h;:a;$!b;p;x;/./Q;Q1' file

or:

或者:

sed '/search-string/,${s//replacement-string/;b};$q1' file

回答by Ronnie and Sandy

I had wanted to truncate a file by quitting when the match was found (and exclude the matching line). This is handy when a process that adds lines at the end of the file may be re-run. "Q;Q1" didn't work but simply "Q1" did, as follows:

我想通过在找到匹配项时退出来截断文件(并排除匹配行)。当在文件末尾添加行的进程可能会重新运行时,这很方便。“Q;Q1”不起作用,而只是“Q1”起作用了,如下所示:

if sed -i '/text I wanted to find/Q1' file.txt then insert blank line at end of file + new lines fi insert just the new lines without the blank line

如果 sed -i '/text I want to find/Q1' file.txt 然后在文件末尾插入空行 + 新行 fi 只插入没有空行的新行

回答by gilbertpilz

These answers are all too complicated. What is wrong with writing a bit of shell script that uses grep to figure out if the thing you want to replace is there then using sed to replace it?

这些答案都太复杂了。编写一些使用 grep 来确定要替换的东西是否存在然后使用 sed 替换它的 shell 脚本有什么问题?

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

回答by Douglas Daseeco

Below is the pattern we use with sed -rnor sed -r.

下面是我们与sed -rnor 一起使用的模式sed -r

The entire search and replace command ("s/.../.../...") is optional. If the search and replace is used, for speed and having already matched $matchRe, we use as fast a $searchRe value as possible, using . where the character does not need to be re-verified and .{$len} for fixed length sections of the pattern.

整个搜索和替换命令 ("s/.../.../...") 是可选的。如果使用搜索和替换,为了速度和已经匹配 $matchRe,我们使用尽可能快的 $searchRe 值,使用 . 其中字符不需要重新验证并且 .{$len} 用于模式的固定长度部分。

The return value for none found is $notFoundExit.

none found 的返回值是 $notFoundExit。

/$matchRe/{s/$searchRe/$replacement/$options; Q}; q$notFoundExit

For the following reasons:

出于以下原因:

  • No time wasted testing for both matched and unmatched case
  • No time wasted copying to or from buffers
  • No superfluous branches
  • Reasonable flexibility
  • 没有时间浪费测试匹配和不匹配的情况
  • 无需浪费时间从缓冲区复制或从缓冲区复制
  • 没有多余的分支
  • 合理的灵活性

Varying the case of Q commands will vary the behavior depending on when the exit should occur. Behaviors involving the application of Boolean logic to a multiple line input requires more complexity in the solution.

改变 Q 命令的大小写将根据退出发生的时间而改变行为。涉及将布尔逻辑应用于多行输入的行为要求解决方案更加复杂。

回答by Dave Cole

As we already know, when sed fails to match then it simply returns its input string - no error has occurred. It is true that a difference between the input and output strings implies a match, but a match does not imply a difference in the strings; after all sed could have simply matched all of the input characters. The flaw is created in the following example

正如我们已经知道的,当 sed 无法匹配时,它只会返回其输入字符串 - 没有发生错误。确实,输入和输出字符串之间的差异意味着匹配,但匹配并不意味着字符串之间的差异;毕竟 sed 可以简单地匹配所有输入字符。该缺陷是在以下示例中创建的

h=$(echo "$g" | sed 's/.*\(abc[[:digit:]]\).*//g')    
if [ ! "$h" = "$g" ]; then    
  echo "1"   
else    
  echo "2"    
fi

where g=Xabc1gives 1, while setting g=abc1gives 2; yet both of these input strings are matched by sed! So, it can be hard to determine whether sed has matched or not. A solution:

其中g=Xabc1给出1,而设置g=abc1给出2;然而这两个输入字符串都被 sed 匹配了!因此,很难确定 sed 是否匹配。一个办法:

h=$(echo "fix${g}ed" | sed 's/.*\(abc[[:digit:]]\).*//g')
if [ ! "$h" = "fix${g}ed" ]; then    
  echo "1"   
else    
  echo "2"    
fi

in which case the 1 is printed if-and-only-if sed has matched.

在这种情况下,如果 sed 匹配,则打印 1。

回答by Chaminda

We have the answer above but it took some time for me work out what is happening. I am trying to provide a simple explanation for basic user of sed like me.

我们有上面的答案,但我花了一些时间才弄清楚发生了什么。我试图为像我这样的 sed 基本用户提供一个简单的解释。

Lets consider the example:

让我们考虑这个例子:

echo "foo" | sed  '/foo/!{q100}; {s/f/b/}'

Here we have two sed commands. First one is '/foo/!{q100}'This command actually check the pattern matching and return exist code 100if no match. Consider following examples, -nis used to silent the output so we only get exist code.

这里我们有两个 sed 命令。第一个是'/foo/!{q100}'此命令实际上检查模式匹配,100如果不匹配则返回存在代码。考虑以下示例,-n用于静默输出,因此我们只获取现有代码。

This example foo matches so exit code return is 0

这个例子 foo 匹配所以退出代码返回是 0

echo "foo" | sed -n '/foo/!{q100}'; echo $?
0

This example input is fooand we try match booso no match and exit code 100is returned

此示例输入是foo,我们尝试匹配,boo因此没有匹配并100返回退出代码

echo "foo" | sed  -n '/boo/!{q100}'; echo $?
100

So if my requirement is only to check a pattern match or not I can use

因此,如果我的要求只是检查模式匹配与否,我可以使用

echo "<input string>" | sed -n '/<pattern to match>/!{q<exit-code>}'

More examples:

更多例子:

echo "20200206" | sed -n '/[0-9]*/!{q100}' && echo "Matched" || echo "No Match"
Matched

echo "20200206" | sed -n '/[0-9]{2}/!{q100}' && echo "Matched" || echo "No Match"
No Match

Second command is '{s/f/b/}'is to replace the fin foowith bwhich I used many times.

第二个命令'{s/f/b/}'是替换ffoob,我用了很多次。