2010-02-13 150 views
5

我正在使用 sed -e "s/\*DIVIDER\*/$DIVIDER/g"用用户指定的字符串替换*DIVIDER*,该字符串存储在$DIVIDER中。问题是我希望它们能够将转义字符指定为分隔符,如\ n或\ t。当我尝试这个时,我最后只是写了字母n或t,等等。使用sed将变量的内容替换为字符串,即使它是转义字符

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

编辑:这是脚本的肉,我必须缺少的东西。

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 

sed的线的长列表中从XML源替换字符,并且最后两个是应该与指定的字符,以取代换行符的那些。我知道用另一个换行符替换换行符似乎是多余的,但这是我能想到的最简单的方法,让他们选择他们自己的分频器。分区替换对于普通字符非常有用。

+4

你的脚本写的不好。很多不必要的sed步骤。显示你正在处理的输入文件,并显示你想要的输出。 – ghostdog74 2010-02-13 18:00:30

回答

7

您可以使用bash逃脱这样的反斜线:

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

的语法是${name/pattern/string}。如果模式以/开始,则name中的pattern的每个发生都被替换为string。否则只会替换第一个事件。

+0

用这个,我最终得到一个双反斜杠和一个插入到流中的“n”。也许这是我处理事物的方式。我将编辑原始帖子以包含更多的脚本。 – vilhalmer 2010-02-13 16:16:22

+1

tangens的解决方案处理反斜杠,但不是\ n或\ t。问题是sed不能识别\ n或\ t。您可以将它们明确地放在DIVIDER中,或者通过另一个过滤器来管理输出以用换行符替换\ n。例如:sed's/\\ n/\ /g' – 2010-02-13 17:13:51

+0

这是一个好主意,我可以通过tr将它返回。谢谢! – vilhalmer 2010-02-14 12:29:32

0

你只需要逃避逃逸字符。

\ n将匹配\ n

\将匹配\

\\将匹配\

+0

我刚刚尝试过\ n并且它最终成了\ n,但它直接打印出来。我如何让sed将它解释为一个转义而不是普通的字符串? – vilhalmer 2010-02-13 15:47:12

1

可能:

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

我打了这个脚本:

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

与在MacOS X '的ksh' 或 '庆典'(而不是 '上海')
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 

运行

1

它似乎是一个简单的替代:

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

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

那么也许这一步可能采取的地方过去两年你的:

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

注意美元符号后的空间。它阻止shell将“$ {s ...”解释为变量名称。

而作为ghostdog74建议,你有太多的电话sed。您可以将大量管道字符更改为反斜杠(续行),并删除除第一个之外的所有“sed”(到处留下“-e”)。(未经测试)

+0

感谢有关不必要的seds调用的信息!我不久前写了这篇文章,并且对一般的sed或shell脚本知之甚少。 – vilhalmer 2010-02-14 12:32:17

+0

我已经尝试将持续和所有在一条线上的调用结合起来,但一些替代品停止工作。它不再删除标签或额外的空间。他们需要进入一些神奇的秩序吗? – vilhalmer 2010-02-14 13:26:28

+0

你有没有离开这个地方? 'sed -n'2,$ p'| sed ...'你正在选择要采取行动的线路。如果你在这里取出管道,它可能不起作用。没有看到数据和你的修改脚本,我不能肯定地说。你应该知道,这种方式疯狂谎言(在HTML上使用正则表达式):http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 – 2010-02-14 15:04:46

0

中使用FreeBSD的sed(例如,在Mac OS X),你必须预处理$分频器用户输入:

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}/"