Использование sed для замены строки содержимым переменной, даже если это escape-символ - PullRequest
5 голосов
/ 13 февраля 2010

я использую sed -e "s/\*DIVIDER\*/$DIVIDER/g" для замены *DIVIDER* на указанную пользователем строку, которая хранится в $DIVIDER. Проблема в том, что я хочу, чтобы они могли указывать escape-символы в качестве разделителя, например \ n или \ t. Когда я пытаюсь это сделать, я просто получаю букву n или t и т. Д.

У кого-нибудь есть идеи, как это сделать? Это будет с благодарностью!

РЕДАКТИРОВАТЬ: Вот суть сценария, я должен что-то упустить.

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, а последние два - те, которые должны заменить символы новой строки указанным символом. Я знаю, что заменить новую строку новой строкой кажется излишним, но это был самый простой способ, который я мог придумать, чтобы позволить им выбрать свой собственный разделитель. Замена делителя отлично работает с обычными символами.

Ответы [ 5 ]

7 голосов
/ 13 февраля 2010

Вы можете использовать bash для удаления обратной косой черты следующим образом:

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

Синтаксис ${name/pattern/string}. Если шаблон начинается с /, каждый случай pattern в name заменяется на string. В противном случае заменяется только первый случай.

1 голос
/ 13 февраля 2010

Вроде бы простая замена:

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

Может быть, я не понимаю, чего вы пытаетесь достичь.

Тогда, возможно, этот шаг мог бы занять место двух ваших последних:

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

Обратите внимание на пробел после знака доллара. Он не позволяет оболочке интерпретировать «$ {s ...» как имя переменной.

И, как подсказывает ghostdog74 , у вас слишком много вызовов на sed. Вы можете изменить множество символов канала на обратную косую черту (продолжение строки) и удалить «sed» из всех, кроме первого (оставьте «-e» везде) (Непроверенные)

1 голос
/ 13 февраля 2010

Может быть:

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

Я играл по этому сценарию:

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

Запускать с 'ksh' или 'bash' (но не с 'sh') в MacOS X:

In:  <<xx\n>>
Out: <<xx\\n>>
In:  <<xxx\\ddd>>
Out: <<xxx\\\\ddd>>
In:  <<xxx>>
Out: <<xxx>>
0 голосов
/ 14 февраля 2010

Используя 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}/"
0 голосов
/ 13 февраля 2010

Вам просто нужно сбежать от спасательного персонажа.

\ n будет соответствовать \ n

\ будет соответствовать \

\\ будет соответствовать \

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...