sed稀有分隔符(除&;|/?…)

sed稀有分隔符(除&;|/?…),sed,delimiter,Sed,Delimiter,我必须对字符串应用Unix命令sed(可以包含#、!、/、?、&@和所有其他字符),该字符串可以包含所有类型的字符(&、|、!、/、?) 它是允许输出错误的复杂分隔符(带两个字符?): sed: -e expression #1, char 22: unknown option to `s' 提前感谢在sed中没有多字符表达式分隔符的选项,但我对此表示怀疑 你需要这个。分隔符字符不应出现在模式中,但如果它出现在正在处理的字符串中,则不是问题。除非你做了一些非常奇怪的事情,否则总会有一些字符没有

我必须对字符串应用Unix命令sed可以包含#、!、/、?、&@和所有其他字符),该字符串可以包含所有类型的字符(&、|、!、/、?)

它是允许输出错误的复杂分隔符(带两个字符?):

sed: -e expression #1, char 22: unknown option to `s'

提前感谢

在sed中没有多字符表达式分隔符的选项,但我对此表示怀疑
你需要这个。分隔符字符不应出现在模式中,但如果它出现在正在处理的字符串中,则不是问题。除非你做了一些非常奇怪的事情,否则总会有一些字符没有出现在你的搜索模式中,可以作为分隔符

输入文件中的字符无关紧要-
sed
可以很好地解析它们。但是,如果您的模式中有大多数常见字符,或者您的模式可能事先不知道,则可能会出现问题

至少在上,您可以使用模式中极不可能存在的不可打印字符作为分隔符。例如,如果您的shell是:

在本例中,Bash
$'\001'
与具有八进制值的字符
001
——在ASCII中是SOH字符(标题的开头)


由于这些字符是控制/不可打印字符,因此它们是否会存在于模式中是值得怀疑的。除非,也就是说,您正在做一些奇怪的事情,比如在没有正确的语言环境设置的情况下修改二进制文件或Unicode文件。

您需要Perl提供的嵌套分隔符功能。这样就可以使用匹配、替换和音译等功能,而不用担心内容中包含分隔符。因为perl是sed的超集,所以您应该能够将它用于sed的任何用途

考虑这一点:

$ perl -nle 'print if /something/' inputs
现在,如果您的
某物
包含斜杠,您就有问题了。解决此问题的方法是更改分隔符,最好是使用括号分隔符。例如,您可以在$WHATEVER shell变量(假设backets是平衡的)中使用您喜欢的任何内容,在这里调用Perl之前,shell会对该变量进行插值:

 $ perl -nle "print if m($WHATEVER)" /usr/share/dict/words
即使您在$whater中正确嵌套了paren,这也是可行的。在Perl中这样正确嵌套的四个括号对是
()
[]
{}
。如果分隔符是平衡的,则它们允许包含该分隔符的任意内容

如果它不平衡,则根本不使用分隔符。如果模式在Perl变量中,则不需要使用match运算符,只要使用
=~
运算符,因此:

$whatever = "some arbitrary string ( / # [ etc";
if ($line =~ $whatever) { ... }

在Jim Lewis的帮助下,我终于在使用sed之前做了一个测试:

if [ `echo $1 | grep '|'` ]; then
    grep ".*$1.*:" $DB_FILE  | sed "s@^.*$1*.*\(:\)@@ "
else
    grep ".*$1.*:" $DB_FILE  | sed "s|^.*$1*.*\(:\)|| "
fi

谢谢你的帮助。我完全不知道您可以使用任何字符作为分隔符。 至少有一半的时间我在路径、代码片段、垃圾字符等方面使用sed和BREs。我最终得到了一大堆可怕的难以读懂的越狱,我甚至不确定这些越狱是否会在我没有想到的组合中死去。但是如果您可以只排除某些字符类(甚至只排除一个字符)

echo'#01Y$#1+!'sed-e'sa$#1+ashita'-e'su#01YuHolyug'

>>天哪

这要容易得多。

另一种方法是使用Shell参数替换

${parameter/pattern/replace}  # substitute replace for pattern once

下面是一个非常复杂的示例,使用sed很困难:

$ parameter="Common sed delimiters: [sed-del]"
$ pattern="\[sed-del\]"
$ replace="[/_%:\\@]"
$ echo "${parameter//$pattern/replace}"
结果是:

Common sed delimiters: [/_%:\@]

但是:这只适用于bash参数,而不适用于
sed
excel的文件。

对用于bash解析的内联分隔符进行转义既麻烦又难以读取(尽管在第一次使用sed时,每个表达式都需要转义分隔符)

要将客户的回答和评论汇总在一起,请执行以下操作:

DELIM=$(echo -en "\001");
sed -n "\\${DELIM}${STARTING_SEARCH_TERM}${DELIM},\\${DELIM}${ENDING_SEARCH_TERM}${DELIM}p" "${FILE}"

此示例返回从
${starting_SEARCH_TERM}
${ENDING_SEARCH_TERM}
的所有结果,这些结果与ASCII代码001的
SOH
(标题开始)字符不匹配。

没有通用的分隔符,但可以通过反斜杠对sed进行转义,以避免将其视为分隔符(至少除非选择反斜杠字符作为分隔符)

根据实际应用程序的不同,在模式和替换中转义这些字符可能很方便

如果您在bash环境中,可以使用bash替换来转义sed分隔符,如下所示:

safe_replace () {
    sed "s/${1//\//\\\/}/${2//\//\\\/}/g"
}
这是很自然的解释,除了奇怪的部分。 对此的解释:

${1//\//\\\/}
${            - bash expansion starts
  1           - first positional argument - the pattern
   //         - bash pattern substitution pattern separator "replace-all" variant
     \/       - literal slash
       /      - bash pattern substitution replacement separator
        \\    - literal backslash
          \/  - literal slash
            } - bash expansion ends
示例用法:

$ input="ka/pus/ta"
$ pattern="/pus/"
$ replacement="/re/"
$ safe_replace "$pattern" "$replacement" <<< "$input"
ka/re/ta
$input=“ka/pus/ta”
$pattern=“/pus/”
$replacement=“/re/”

$safe_替换“$pattern”“$replacement”至少,告诉我们您给sed的导致错误的字符串。在sed传递的字符串可以包含#、!、/、?、&@和所有其他字符。我正在做一些非常奇怪的事情,是的。我正在测试所有类型的字符。@tKnowed:只有Perl而不是sed提供独立于分隔符的匹配。因为Perl是一个正确的超集对于sed,这可能就足够了。前几天我遇到了这个问题,我不认为我所做的是非常奇怪的:我试图删除一行包含任意字符串
$STR
,例如
sed-I-e'/'“$STR”“/d'$FILE
。或者有更好的习惯用法用于上述内容吗?不可打印的字符可能会出现在搜索模式中,但感谢提示“极不可能”与不可能的情况不同。在sed中,如果没有某些分隔符,则无法进行匹配,如果该分隔符在模式中,则始终会导致问题。但是,在Perl中,您可以。这非常有效。@Tknow-处理的是什么类型的文本?此解决方案几乎完美地处理了大多数数据集。您是在处理文本还是二进制?空字节i它对于处理文件名是安全的,但是对于实际的文本数据,没有比非安全字符更安全的字符了-
${1//\//\\\/}
${            - bash expansion starts
  1           - first positional argument - the pattern
   //         - bash pattern substitution pattern separator "replace-all" variant
     \/       - literal slash
       /      - bash pattern substitution replacement separator
        \\    - literal backslash
          \/  - literal slash
            } - bash expansion ends
$ input="ka/pus/ta"
$ pattern="/pus/"
$ replacement="/re/"
$ safe_replace "$pattern" "$replacement" <<< "$input"
ka/re/ta