2014-09-01 3 views
2

У меня странное поведение в сценарии bash, который я не понимаю.Bash escape-скрипт & группа захвата sed

В основном в коде ниже я пытаюсь избежать мета-символы ...

while IFS=, read _type _content; do 

    if [ -z "$patternfilter" ]; then 
    if [ "$_type" == "rex" ]; then 
     patternfilter="$_content" 
    elif [ "$_type" == "txt" ]; then 
     patternfilter="`echo "$_content" | sed -re 's/([-^[{}()*+/.,;?$|#\\])/\\\1/g' -e 's/]/\\]/g'`" 
    fi 
    else 
    if [ "$_type" == "rex" ]; then 
     patternfilter="$patternfilter|$_content" 
    elif [ "$_type" == "txt" ]; then 
     patternfilter="$patternfilter|`echo "$_content" | sed -re 's/([-^[{}()*+/.,;?$|#\\])/\\\1/g' -e 's/]/\\]/g'`" 
    fi 
    fi 
done < $patternfile 

outpout дать мне следующее:

blabal \ 1bla \ 1blabla \ 1toto \ 1com

Вместо:

blabal \ (бла \) блабла \ [тото \] \. Ком

Если я вхожу непосредственно в консоли код он работает ... Я что-то пропустил, но я не знаю, что.

[root]# patternfilter="blabal(bla)blabla[toto].com" 
[root]# echo "$patternfilter" | sed -re 's/([-^[{}()*+/.,;?$|#\\])/\\\1/g' -e 's/]/\\]/g' 
blabal\(bla\)blabla\[toto\]\.com 

ответ

4

Вы не можете надежно избегать символов в sed, независимо от того, следует ли экранировать символ, который должен быть экранирован. Кроме того, оболочка - это среда, из которой можно вызвать инструменты. Стандартный инструмент UNIX для управления текстом - awk. Просто попросите свой вызов shell awk сделать все. Кстати, ваше использование `...` вместо $(...) будет интерпретировать двойные экраны, и ваше использование чтения без -r будет расширять экраны.

SInce awk может работать как с строками, так и с RE, вам почти наверняка не придется ничего избегать, поскольку обычная причина избежать символов - попытаться сделать ваш инструмент, который работает только на REs, работает на строках, что является невозможная задача.

Если вы сообщите нам, что вы пытаетесь сделать с помощью patternfilter, а также пример ввода и ожидаемого вывода, мы можем показать вам, как это сделать просто и надежно.

2

Проверьте следующий сценарий:

while IFS=, read -r line; do 
    result1="`echo "$line" | sed -re 's/([-^[{}()*+/.,;?$|#\\])/\\\1/g' -e 's/]/\\]/g'`" 
    echo "1=$result1=" 

    result2="$(echo "$line" | sed -re 's/([-^[{}()*+/.,;?$|#\\])/\\\1/g' -e 's/]/\\]/g')" 
    echo "2=$result2=" 
done <<'EOF' 
blabal(bla)blabla[toto].com 
EOF 

печатает:

1=blabal\1bla\1blabla\1toto]\1com= 
2=blabal\(bla\)blabla\[toto\]\.com= 

вместо внесения из обратных кавычек использовать $(), как и в result2=... линии. (И всегда использовать -r для read -r)

Вы можете избежать проще, с printf "%q" такой,

while IFS=, read _type _content; do 
res=$(printf "%q" "$_content") 
echo "==$res==" 
done <<EOF 
txt,blabal(bla)blabla[toto].com 
EOF 

какие отпечатки

==blabal\(bla\)blabla\[toto\].com== 

Но, читайте @ ответ EdMorton в.

+0

Обратите внимание, что без чтения '-r' будут интерпретировать обратную косую черту. Попробуйте это с помощью 'a \ tb' с и без' -r'. –

+0

@EdMorton В ответе '(и всегда использовать -r для чтения -r)' предлагает это. :) – jm666

+2

А я пропустил это. Почему бы не использовать его в своем скрипте, вместо того чтобы не использовать его, но заявив, что всегда его используете? –