返回不匹配的sed代码

时间:2013-04-12 07:01:34

标签: linux json sed

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

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

谢谢!

9 个答案:

答案 0 :(得分:48)

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

所以如果你有:

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

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

解决方法

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

 q [exit-code]

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

匹配案例:

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

无与伦比的案例:

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

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

修改

我必须补充一点,上面的例子只适用于单行处理。我不知道你的具体要求。当你想获得exit 1时。单行不匹配或整个文件。如果整个文件不匹配,您可以考虑使用awk,甚至在文本处理之前执行grep ...

答案 1 :(得分:47)

这可能适合你(GNU sed):

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

如果找到search-string,则会将其替换为replacement-string,文件结束时sed将以0返回代码退出。如果不进行替换,则返回码为1

更详细的解释:

用户可以使用两个寄存器:当前行加载到的模式空间(PS)(减去换行符)和一个最初为空的称为保持空间(HS)的备用寄存器。 / p>

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

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

首先替换s//replacement-string/(sed使用最后一个正则表达式,即search-string,如果左侧是空的,那么s//replacement-strings/search-string/replacement-string/相同,并且在此之后,h命令会复制PS并将其放入HS中。

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

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

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

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

另一种选择:

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

或:

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

答案 2 :(得分:20)

这些答案都太复杂了。编写一些使用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

答案 3 :(得分:1)

以下是我们与sed -rnsed -r一起使用的模式。

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

找不到的返回值是$ notFoundExit。

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

出于以下原因:

  • 没有浪费时间测试匹配和不匹配的案例
  • 没有时间浪费复制到缓冲区或从缓冲区复制
  • 没有多余的分支
  • 合理的灵活性

改变Q命令的大小会改变行为,具体取决于何时应该退出。涉及将布尔逻辑应用于多线输入的行为需要在解决方案中更复杂。

答案 4 :(得分:1)

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

让我们考虑示例:

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

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

此示例foo匹配,因此退出代码返回为0

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

此示例输入为foo,我们尝试匹配boo,因此不返回匹配和退出代码100

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

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

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

更多示例:

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

第二个命令是'{s/f/b/}',它是用我多次使用的f替换foo中的b

答案 5 :(得分:1)

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

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

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

答案 6 :(得分:0)

我想在找到匹配项时通过退出截断文件(并排除匹配的行)。当重新运行在文件末尾添加行的进程时,这很方便。 &#34; Q; Q1&#34;没有工作,只是&#34; Q1&#34;做了,如下:

如果sed -i&#39; / text我想找/ Q1&#39; file.txt的 然后    在文件末尾插入空行+新行 科幻 只插入没有空白行的新行

答案 7 :(得分:0)

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

g=Xabc1

其中g=abc1给出1,而设置h=$(echo "fix${g}ed" | sed 's/.*\(abc[[:digit:]]\).*/\1/g') if [ ! "$h" = "fix${g}ed" ]; then echo "1" else echo "2" fi 给出2;然而这两个输入字符串都是由sed匹配的!因此,很难确定sed是否匹配。解决方案:

# Input: date in "dd.mm.yyyy hh:mm:ss" format;
# returns true iff the date is more than (24 * days) hours
# in the past relative to `now`
def older(days):
  (now - (strptime("%d.%m.%Y %T") | mktime)) #  seconds 
  >  (days*24*3600);

在这种情况下,只有当sed匹配时才会打印1。

答案 8 :(得分:0)

对于任意数量的输入行:

sed --quiet 's/hello/HELLO/;t1;b2;:1;h;:2;p;${g;s/..*//;tok;q1;:ok}'

在匹配时填充保留空间,并在最后一行之后检查它。 如果文件中没有匹配项,则返回状态 1

  • s/hello/HELLO - 替代检查
  • t1 - 如果替换成功,则跳转到标签 1
  • b2 - 无条件跳转到标签 2
  • :1 - 标签 1
  • h - 复制模式以保留空间(替换成功时)
  • :2 - 标签 2
  • p - 无条件打印模式空间
  • ${ ... } - 匹配最后一行,评估内部块
  • g - 将保持空间复制到模式空间(如果第一次替换之前成功则非空)
  • s/..*// - 虚拟替换,设置分支标志
  • tok - 跳转到标签 ok(如果虚拟替换在非空保持空间上成功)
  • q1 - 以错误状态 1 退出
  • :ok - 标签 ok