bash 使用 sed 将字符串替换为变量的内容,即使它是转义字符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2257983/
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-09-17 21:40:17  来源:igfitidea点击:

Using sed to replace a string with the contents of a variable, even if it's an escape character

bashstringsed

提问by vilhalmer

I'm using sed -e "s/\*DIVIDER\*/$DIVIDER/g"to replace *DIVIDER*with a user-specified string, which is stored in $DIVIDER. The problem is that I want them to be able to specify escape characters as their divider, like \n or \t. When I try this, I just end up with the letter n or t, or so on.

我正在使用 用户指定的字符串sed -e "s/\*DIVIDER\*/$DIVIDER/g"替换*DIVIDER*,该字符串存储在$DIVIDER. 问题是我希望他们能够将转义字符指定为分隔符,例如 \n 或 \t。当我尝试这个时,我只是以字母 n 或 t 结束,等等。

Does anyone have any ideas on how to do this? It will be greatly appreciated!

有没有人对如何做到这一点有任何想法?将不胜感激!

EDIT: Here's the meat of the script, I must be missing something.

编辑:这是脚本的主要内容,我一定遗漏了一些东西。

curl --silent "$URL" > tweets.txt

if [[ `cat tweets.txt` == *\<error\>* ]]; then
    grep -E '(error>)' tweets.txt | \
    sed -e 's/<error>//' -e 's/<\/error>//' |
    sed -e 's/<[^>]*>//g' |

head $headarg | sed G | fmt

else
    echo $REPLACE | awk '{gsub(".", "\\&");print}'
    grep -E '(description>)' tweets.txt | \
    sed -n '2,$p' | \
    sed -e 's/<description>//' -e 's/<\/description>//' |
    sed -e 's/<[^>]*>//g' |
    sed -e 's/\&amp\;/\&/g' |
    sed -e 's/\&lt\;/\</g' |
    sed -e 's/\&gt\;/\>/g' |
    sed -e 's/\&quot\;/\"/g' |
    sed -e 's/\&....\;/\?/g' |
    sed -e 's/\&.....\;/\?/g' |
    sed -e 's/^  *//g' |
    sed -e :a -e '$!N;s/\n/\*DIVIDER\*/;ta' |   # Replace newlines with *divider*.
    sed -e "s/\*DIVIDER\*/${DIVIDER//\/\\}/g" |          # Replace *DIVIDER* with the actual divider.

    head $headarg | sed G
fi

The long list of sed lines are replacing characters from an XML source, and the last two are the ones that are supposed to replace the newlines with the specified character. I know it seems redundant to replace a newline with another newline, but it was the easiest way I could come up with to let them pick their own divider. The divider replacement works great with normal characters.

一长串 sed 行正在替换来自 XML 源的字符,最后两个是应该用指定字符替换换行符的行。我知道用另一个换行符替换换行符似乎是多余的,但这是我能想出的让他们选择自己的分隔符的最简单方法。分隔符替换适用于普通字符。

回答by tangens

You can use bash to escape the backslash like this:

您可以使用 bash 来转义反斜杠,如下所示:

sed -e "s/\*DIVIDER\*/${DIVIDER//\/\\}/g"

The syntax is ${name/pattern/string}. If pattern begins with /, every occurence of patternin nameis replaced by string. Otherwise only the first occurence is replaced.

语法是${name/pattern/string}. 如果模式以 开头/,则每次出现的patterninname都会替换为string。否则只替换第一次出现。

回答by Jonathan Leffler

Maybe:

也许:

case "$DIVIDER" in
(*\*) DIVIDER=$(echo "$DIVIDER" | sed 's/\/\\/g');;
esac

I played with this script:

我玩过这个脚本:

for DIVIDER in 'xx\n' 'xxx\ddd' "xxx"
do
    echo "In:  <<$DIVIDER>>"
    case "$DIVIDER" in     (*\*) DIVIDER=$(echo "$DIVIDER" | sed 's/\/\\/g');;
    esac
    echo "Out: <<$DIVIDER>>"
done

Run with 'ksh' or 'bash' (but not 'sh') on MacOS X:

在 MacOS X 上使用 'ksh' 或 'bash'(但不是 'sh')运行:

In:  <<xx\n>>
Out: <<xx\n>>
In:  <<xxx\ddd>>
Out: <<xxx\\ddd>>
In:  <<xxx>>
Out: <<xxx>>

回答by Paused until further notice.

It seems to be a simple substitution:

这似乎是一个简单的替换:

$ d='\n'
$ echo "a*DIVIDER*b" | sed "s/\*DIVIDER\*/$d/"
a
b

Maybe I don't understand what you're trying to accomplish.

也许我不明白你想要完成什么。

Then maybe this step could take the place of the last two of yours:

那么也许这一步可以代替你的最后两个步骤:

sed -n ":a;$ {s/\n/$DIVIDER/g;p;b};N;ba"

Note the space after the dollar sign. It prevents the shell from interpreting "${s..." as a variable name.

注意美元符号后面的空格。它可以防止 shell 将“${s...”解释为变量名。

And as ghostdog74suggested, you have way too many calls to sed. You may be able to change a lot of the pipe characters to backslashes (line continuation) and delete "sed" from all but the first one (leave the "-e" everywhere). (untested)

正如ghostdog74建议的那样,您对sed. 您可以将许多管道字符更改为反斜杠(行继续)并从除第一个之外的所有字符中删除“sed”(将“-e”保留在任何地方)。(未经测试)

回答by carlo

Using FreeBSD sed (e.g. on Mac OS X) you have to preprocess the $DIVIDER user input:

使用 FreeBSD sed(例如在 Mac OS X 上)您必须预处理 $DIVIDER 用户输入:

d='\n'
d='\t'
NL=$'\\n'
TAB=$'\\t'
d="${d/\n/${NL}}"
d="${d/\t/${TAB}}"
echo "a*DIVIDER*b" | sed -E -e "s/\*DIVIDER\*/${d}/"

回答by Daniel Ice

You just need to escape the escape char.

你只需要逃避转义字符。

\n will match \n

\n 将匹配\n

\ will match \

\ 将匹配 \

\\ will match \

\\ 将匹配 \