Bash 使用可能包含斜杠的任意变量进行sed

Bash 使用可能包含斜杠的任意变量进行sed,bash,shell,sed,Bash,Shell,Sed,我尝试以以下方式使用sed: VAR=`echo $STRING | sed s/$TOKEN/$REPLACEMENT/` 不幸的是,我遇到了一个$REPLACEMENT可能包含斜杠的情况。这会导致bash抱怨,因为它(shell)可能会将其扩展为以下内容: #given $VAR=I like bananas, $TOKEN=bananas, and $REPLACEMENT=apples/oranges VAR=`echo I like bananas | sed s/bananas/a

我尝试以以下方式使用sed:

VAR=`echo $STRING | sed s/$TOKEN/$REPLACEMENT/`
不幸的是,我遇到了一个$REPLACEMENT可能包含斜杠的情况。这会导致bash抱怨,因为它(shell)可能会将其扩展为以下内容:

#given $VAR=I like bananas, $TOKEN=bananas, and $REPLACEMENT=apples/oranges
VAR=`echo I like bananas | sed s/bananas/apples/oranges/`
因此,现在sed被赋予了一个包含太多/(的)的无效参数。有什么好办法处理这个问题吗?

这是解决办法

VAR="I like bananas"
TOKEN="bananas"
REPLACEMENT="apples/oranges"
echo $VAR |sed "s@$TOKEN@$REPLACEMENT@"

I like apples/oranges
这是解决办法

VAR="I like bananas"
TOKEN="bananas"
REPLACEMENT="apples/oranges"
echo $VAR |sed "s@$TOKEN@$REPLACEMENT@"

I like apples/oranges

您可以使用任何您喜欢的分隔符
“s!$TOKEN!$REPLACEMENT!”
“s%$TOKEN%$REPLACEMENT%”
是流行的替代方案

当然,在一般情况下,如果输入可以包含任何字符,那么就回到原点。您可以切换到一种不会如此轻率地混合代码和数据的语言。。。事实上,包括外壳本身

echo "${VAR/$TOKEN/$REPLACEMENT}"

(这是一个Bash扩展。它在其他一些shell中可用,但在经典的Bourne shell中不可用。)

您可以使用任何您喜欢的分隔符
“s!$TOKEN!$REPLACEMENT!”
“s%$TOKEN%$REPLACEMENT%”
是流行的替代方案

当然,在一般情况下,如果输入可以包含任何字符,那么就回到原点。您可以切换到一种不会如此轻率地混合代码和数据的语言。。。事实上,包括外壳本身

echo "${VAR/$TOKEN/$REPLACEMENT}"

(不过,这是一个Bash扩展。它在其他一些shell中可用,但在经典的Bourne shell中不可用。)

您不能可靠地使用sed进行此操作,因为:

  • 您通常找不到保证不会出现的字符 在任何$TOKEN或$REPLACEMENT字符串中,以及
  • sed无法搜索字符串-它始终搜索正则表达式和 因此,$TOKEN中的任何RE元字符都将按此方式计算,并且 无法可靠地实现代码来转义它们(尽管有很多 人们已经尝试过了)
  • 因此,只需使用awk:

    VAR=$(echo "$STRING" | awk -v t="$TOKEN" -v r="$REPLACEMENT" 'idx=index($0,t) {$0 = substr($0,1,idx-1) r substr($0,idx+length(t))} 1')
    
    这将适用于3个字符串中的任何字符,除了$STRING中的换行符

    如果没有
    echo
    ,它也将处理$STRING中的换行符:

    VAR=$(awk -v s="$STRING" -v t="$TOKEN" -v r="$REPLACEMENT" '
    BEGIN {
        if (idx = index(s,t))
            s = substr(s,1,idx-1) r substr(s,idx+length(t))
        print s
    }')
    

    您无法可靠地使用sed进行此操作,因为:

  • 您通常找不到保证不会出现的字符 在任何$TOKEN或$REPLACEMENT字符串中,以及
  • sed无法搜索字符串-它始终搜索正则表达式和 因此,$TOKEN中的任何RE元字符都将按此方式计算,并且 无法可靠地实现代码来转义它们(尽管有很多 人们已经尝试过了)
  • 因此,只需使用awk:

    VAR=$(echo "$STRING" | awk -v t="$TOKEN" -v r="$REPLACEMENT" 'idx=index($0,t) {$0 = substr($0,1,idx-1) r substr($0,idx+length(t))} 1')
    
    这将适用于3个字符串中的任何字符,除了$STRING中的换行符

    如果没有
    echo
    ,它也将处理$STRING中的换行符:

    VAR=$(awk -v s="$STRING" -v t="$TOKEN" -v r="$REPLACEMENT" '
    BEGIN {
        if (idx = index(s,t))
            s = substr(s,1,idx-1) r substr(s,idx+length(t))
        print s
    }')
    

    您应该用括号替换旧的和过时的背面tic
    $(…)
    示例:
    VAR=$(echo$STRING | sed s/$TOKEN/$REPLACEMENT/)
    可能的重复项比这更糟糕。如果$TOKEN包含RE元字符(
    *
    ,等等),那么sed也将对它们进行评估。这就是你想要的吗?你应该用括号替换旧的和过时的背面tic
    $(…)
    例如:
    VAR=$(echo$STRING | sed s/$TOKEN/$REPLACEMENT/)
    可能的重复比这更糟糕。如果$TOKEN包含RE元字符(
    *
    ,等等),那么sed也将对它们进行评估。这就是您想要的吗?另一个好的选择是不可打印的ascii控制字符,它们不太可能出现在字符串中:
    printf-v foo的\x01%s\x01%s\x01的“搜索字符串”replacsestring;echo“$string”| sed-e“$foo”
    @这是另一个有趣的想法,但我不敢推荐,因为它肯定会在各种
    sed
    实现中崩溃。我对此表示怀疑。这既违反了POSIX,而且在C中实现起来比简单地允许它更困难。至少在OSX上,我无法让它工作,尽管障碍是
    printf
    似乎不想接受
    \x01
    格式的控制字符。使用文字控件—一个字符—允许我解决这个问题。但无论如何,很难想出完全可移植的东西(这不会比简单地使用Perl更复杂)。另一个好的选择是不可打印的ascii控制字符,它们特别不可能出现在字符串中:
    printf-vfoo's\x01%s\x01%s\x01's“searchstring”“replacestring”;echo“$string”| sed-e“$foo”
    @这是另一个有趣的想法,但我不敢推荐,因为它肯定会在各种
    sed
    实现中崩溃。我对此表示怀疑。这既违反了POSIX,而且在C中实现起来比简单地允许它更困难。至少在OSX上,我无法让它工作,尽管障碍是
    printf
    似乎不想接受
    \x01
    格式的控制字符。使用文字控件—一个字符—允许我解决这个问题。但是无论如何,很难想出完全可移植的东西(这不会比简单地使用Perl更复杂)。