sed 命令在带有参数的脚本中失败

sed 命令在带有参数的脚本中失败

我正在尝试执行两步字符串编辑:

  1. 匹配字符串“payload”。如果找到,则添加一些“#if #endif”代码,如输出文件中所示。
  2. 然后复制包含“payload”的行,将其替换为“upper_payload”,然后将其粘贴到“if endif”条件中。

输入文件:

Let's see if this works or not payload.
alskdjaslkdjn.
aslkdjbnalkgfjbaglbjbjdgfsbkgjbsg;
Also here is another_payload.
alskdjbnalgkjb.
kjhsdfjlkgfjlknbsgdfljkbgsbljk((*&)(&;

预期输出文件:

Let's see if this works or not payload.
#if defined(NV_C2C_UPPER_PD)
Let's see if this works or not upper_payload.
#endif
alskdjaslkdjn.
aslkdjbnalkgfjbaglbjbjdgfsbkgjbsg;
Also here is another_payload.
#if defined(NV_C2C_UPPER_PD)
Also here is another_upper_payload.
#endif
alskdjbnalgkjb.
kjhsdfjlkgfjlknbsgdfljkbgsbljk((*&)(&;

我最终在 shell 文件中提出了以下代码,以便我可以在多个文本文件上运行它:

#!/bin/csh -f
sed -i '/payload/a #if defined(NV_C2C_UPPER_PD)\n#endif' $1
sed -i "/NV_C2C_UPPER_PD/a `sed -n '/payload/s/payload/upper_payload/p' $1`" $1

使用上面的 shell 脚本,当我传递如下命令时:

> ./my_shell.sh test.txt

文本文件被修改为以下输出:

Let's see if this works or not payload.
#if defined(NV_C2C_UPPER_PD)
Let's see if this works or not upper_payload.
#endif
alskdjaslkdjn.
aslkdjbnalkgfjbaglbjbjdgfsbkgjbsg;
Also here is another_payload.
#if defined(NV_C2C_UPPER_PD)
Let's see if this works or not upper_payload.
#endif
alskdjbnalgkjb.
kjhsdfjlkgfjlknbsgdfljkbgsbljk((*&)(&;

它还在终端上给出此错误/警告:

sed: can't read Also here is another_upper_payload.: No such file or directory

在输出中,我们可以观察到第二个“upper_payload”替换不正确,因为行复制不正确。它复制了第一行,而不是包含“another_payload”的新行。

我尝试了不同的选择,但未能解决这个问题。希望得到一些帮助。

答案1

不要尝试调用另一个sed进程来为其中一个sed表达式创建输入,而是考虑s///在找到触发子字符串 ( ) 后立即使用命令重新组织当前行payload

/payload/!b

s/.*/&\
#if defined(NV_C2C_UPPER_PD)\
&\
#endif/

s/payload/upper_&/2

上面的sed编辑脚本首先跳过包含触发字符串的任何行。当不带标签使用时,(“branch”)命令b会跳到脚本的最后。

在剩余的行上,我们将整个内容替换为自身,然后是该#if行,再次替换原始行,然后是该#endif行。s///如果换行符如上所示进行转义,则可以使用该命令插入换行符(GNU 也sed允许使用 插入文字换行符\n)。

然后,该字符串的第二次出现将在单独的替换中payload添加到该字符串的前面。upper_

此解决方案假设触发字符串不会在一行中多次出现,或者最后一次替换不会替换正确的子字符串。

在命令行上,

sed -e '/payload/!b' \
    -e 's/.*/&\
#if defined(NV_C2C_UPPER_PD)\
&\
#endif/' \
    -e 's/payload/upper_&/2' file

或者,为脚本使用单独的脚本文件,

sed -f script file

或者,使用脚本的此处文档,

sed -f /dev/stdin file <<'SED_SCRIPT'
/payload/!b

s/.*/&\
#if defined(NV_C2C_UPPER_PD)\
&\
#endif/

s/payload/upper_&/2
SED_SCRIPT

或者,使用 GNU sed

sed -e '/payload/!b' \
    -e 's/.*/&\n#if defined(NV_C2C_UPPER_PD)\n&\n#endif/' \
    -e 's/payload/upper_&/2' file

结果:

Let's see if this works or not payload.
#if defined(NV_C2C_UPPER_PD)
Let's see if this works or not upper_payload.
#endif
alskdjaslkdjn.
aslkdjbnalkgfjbaglbjbjdgfsbkgjbsg;
Also here is another_payload.
#if defined(NV_C2C_UPPER_PD)
Also here is another_upper_payload.
#endif
alskdjbnalgkjb.
kjhsdfjlkgfjlknbsgdfljkbgsbljk((*&)(&;

答案2

你可以试试这个sed

$ sed -i 's/\(.*\)\(payload\)\(.*\)/&\n#if defined(NV_C2C_UPPER_PD)\n\1upper_\2\3\n#endif/ ' input_file

\(.*\)\(payload\)在这里,匹配被分为 2 组,这样我们就可以在返回时轻松地反向引用它们

&将返回未更改的完整匹配项

\1upper_\2这是我们按照要求的顺序返回分组的地方,第一个组一直匹配到payload允许upper_在之前插入payload

输出

$ sed 's/\(.*\)\(payload\)\(.*\)/&\n#if defined(NV_C2C_UPPER_PD)\n\1upper_\2\3\n#endif/' input_file
Let's see if this works or not payload
#if defined(NV_C2C_UPPER_PD)
Let's see if this works or not upper_payload
#endif.
alskdjaslkdjn.
aslkdjbnalkgfjbaglbjbjdgfsbkgjbsg;
Also here is another_payload
#if defined(NV_C2C_UPPER_PD)
Also here is another_upper_payload
#endif.
alskdjbnalgkjb.
kjhsdfjlkgfjlknbsgdfljkbgsbljk((*&)(&;

答案3

这里已经有很好的sed解决方案,但我个人更喜欢awk这个:

awk \
-v if='#if defined(NV_C2C_UPPER_PD)' \
-v endif='#endif' \
'
/payload/{
  line=$0
  gsub("payload","upper_payload",$0);
  printf "%s\n%s\n%s\n%s\n",$line,if,$0,endif
  next
}
1' file

答案4

仅使用 POSIXly 构造的一种方法:

sed -e 'p
  /payload/!d
  s//upper_&/
  i\
#if defined(NV_C2C_UPPER_PD)
  a\
#endif
' file

如果您不希望转义换行符,您可以执行以下操作,同时仍然符合 POSIXly:

sed -e 'p
  /payload/!d
  s//upper_&/
  H;s/.*//;x;G
  s/^/#if defined(NV_C2C_UPPER_PD)/
  s/$/#endif/
' file

相关内容