2015-12-09 7 views
0

Я пытаюсь написать функцию Баш, что бы избежать всех двойных кавычек в одинарные кавычки, например:BASH избежать двойные кавычки в одинарные кавычки

'I need to escape "these" quotes with backslashes' 

станет

'I need to escape \"these\" quotes with backslashes' 

Мои взять на себя это было:

  1. найти пары одинарных кавычек в входе и извлечь их с Grep
  2. трубы в СЭД, избежать двойные кавычки
  3. Sed снова весь вход и заменить матч Grep с sedded матча

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

Код сценария CopyPaste:

# $1 - Full name, $2 - minified name 
adjust_quotes() 
{ 
    SINGLE_QUOTES=`grep -Eo "'.*'" $2` 
    ESCAPED_QUOTES=`echo $SINGLE_QUOTES | sed 's|"|\\\\"|g'` 
    sed -r "s|'.*'|$ESCAPED_QUOTES|g" "$2" > "$2.escaped" 
    mv "$2.escaped" $2 
    echo "Quotes escaped within single quotes on $2" 
} 

Случайные дополнительные вопросы:

  • В консоли, спасаясь котировку только две обратные косые черты работает, но когда код введен в сценарии - мне нужно 4. Мне бы хотелось знать
  • Мог ли я изменить этот код в цикле, чтобы избежать все пары одиночных кавычек, один за другим до EOF?

Спасибо!

P.S. Я знаю, что это, вероятно, будет легче сделать, например. python, но мне действительно нужно сохранить его в bash.

+1

Возможно, лучший вопрос, почему вам нужно избегать кавычек в первую очередь? – chepner

+0

Я не уверен, что ваши критерии для «держать его в bash», так как вы, похоже, в порядке с 'sed' и' grep'. Является 'awk' ок? Как насчет 'perl'? – rici

+0

@chepner - нет, это не так. Если бы это было так, я бы попросил об этом. –

ответ

0

Вот чистый раствор Баш, который делает преобразование на стандартный ввод, печать на стандартный вывод. Он считывает весь ввод в память, поэтому он не будет работать с действительно огромными файлами.

escape_enclosed_quotes() (
    IFS=\' 
    read -d '' -r -a fields 
    for ((i=1; i<${#fields[@]}; i+=2)); do 
    fields[i]=${fields[i]//\"/\\\"} 
    done 
    printf %s "${fields[*]}" 
) 

Я намеренно приложило тело функции в скобках, а не фигурные скобки, для того, чтобы заставить тело работать в субоболочке. Это ограничивает модификацию IFS телу, а также неявно делает переменные локальными.

Функция использует read встроенную команду, чтобы прочитать весь входной (так как линия разделитель установлен в NUL с -d '') в массив (-a), используя апостроф в качестве разделителя полей (IFS=\'). Результат состоит в том, что части ввода, окруженные одинарными кавычками, находятся в нечетных положениях массива, поэтому функция выполняет циклические операции над нечетными индексами, чтобы сделать замену только для этих полей. Я использую синтаксис find-and-replace bash вместо переноса на внешнюю утилиту, например sed.

Это существо Баш, есть несколько подводных камней:

  1. Если файл содержит NUL, остальная часть файла будет игнорироваться.
  2. Если последняя строка файла не заканчивается символом новой строки, а последний символ этой строки является отдельной цитатой, она не будет выводиться.

Оба вышеуказанных условия невозможны в переносном текстовом файле, поэтому, вероятно, это нормально. Тем не менее, стоит обратить внимание.


Дополнительный вопрос: почему дополнительные обратные косые необходимы в

ESCAPED_QUOTES=`echo $SINGLE_QUOTES | sed 's|"|\\\\"|g'` 

Ответ: Это не имеет ничего общего с этой линии, находящейся в сценарии. Это связано с использованием backticks (...) для замены команд, а также необычной и часто непредсказуемой обработкой обратных косых черт внутри backticks. Этот синтаксис устарел. Do not use it. (. Не даже если вы видите кого-то использовать его в каком-то случайном, например в Интернете) Если вы использовали рекомендованный $(...) синтаксис для подстановки команд, она работала бы, как ожидалось:

ESCAPED_QUOTES=$(echo $SINGLE_QUOTES | sed 's|"|\\"|g') 

(Подробнее информация находится в Bash FAQ, приведенном выше.)

+0

Это богатство дополнительной информации, которую я не ожидал, но это определенно приветствуется! Спасибо. –

0

Использование BASH строка замены:

s='I need to escape "these" quotes with backslashes' 
r="${s//\"/\\\"}" 
echo "$r" 
I need to escape \"these\" quotes with backslashes 
Смежные вопросы