Как экранировать специальные символы в строке?

16

Предполагая, что $fileон содержит значение имени файла, скажем Dr' A.tif. В программировании на Bash, как я могу избежать одиночной кавычки и любого другого специального символа $fileбез удаления специального символа?

Обновление от 9 июля 2014 г.

По запросу @Gilles , следующий фрагмент кода, который не может обработать Dr' A.tif:

files=$(find /path/ -maxdepth 1 -name "*.[Pp][Dd][Ff]" -o -name "*.[Tt][Ii][Ff]")
echo "${files}" > ${TEMP_FILE}
while read file
do
   newfile=$(echo "${file}" | sed 's, ,\\ ,g') ## line 1
done < ${TEMP_FILE}

После того, как я опробовал в ответ от @Patrick на line 1, кажется, работает для меня. Но если у меня есть файл, такой как Dr\^s A.tif, printfкоманда, кажется, не помогает, она показывает мне Dr\^s\ A.tif. Если я вручную попробую это на консоли, как это:

printf "%q" "Dr\^s A.tif"

У меня будет такой вывод:

Dr\\\^s\ A.tif

Есть идеи, как с этим справиться?

huahsin68
источник
3
в каком контексте вы собираетесь использовать $ file? или это проблема присвоения строки со специальным символом $ file?
ограбить
На самом деле команда find возвращает мне список файлов. И затем я перебираю этот список файлов в переменную $ file.
huahsin68
2
Здесь вам дали несколько правильных ответов, но они, вероятно, не являются ответами на вопрос, который вы действительно задаете. Из вашего комментария здесь я сильно подозреваю, что вы на неправильном пути. Мы не можем вам сильно помочь, потому что вы не показываете свой код. Тем не менее, я рекомендую вам прочитать Почему мой сценарий оболочки задыхается от пробелов или других специальных символов? в качестве фона. Покажите свой сценарий и объясните, что вы хотите сделать.
Жиль "ТАК - перестать быть злым"

Ответы:

14

Вы можете использовать printfвстроенную функцию %qдля этого. Например:

$ file="Dr' A.tif"
$ printf '%q\n' "$file"
Dr\'\ A.tif

$ file=' foo$bar\baz`'
$ printf '%q\n' "$file"
\ foo\$bar\\baz\`

Из документации bash printf:

In addition to the standard format specifications described in printf(1)
and printf(3), printf interprets:

 %b       expand backslash escape sequences in the corresponding argument
 %q       quote the argument in a way that can be reused as shell input
 %(fmt)T  output the date-time string resulting from using FMT as a format
          string for strftime(3)
Патрик
источник
Это не работает в определенных случаях. Например, когда вам нужно сохранить двойные кавычки.
user3467349
@ user3467349 это работает очень хорошо с кавычками. Могу поспорить, что вы пытаетесь что-то вроде printf '%s' "foo". Вы должны сначала понять, как работает синтаксический анализ в оболочке. См. Gnu.org/software/bash/manual/bash.html#Shell-Operation # 2 до того, как # 6.
Патрик
Не могли бы вы привести пример этой строки, напечатанной printfбез каких-либо других манипуляцийIt doesn't have a: ""
user3467349
Ваша проблема не имеет ничего общего с printf. Ваша проблема в том, что вы не хотите, чтобы оболочка анализировала вашу строку. Чтобы сделать это, вы должны передать свой ввод в оболочку так, чтобы он даже не пытался ее проанализировать. Один из способов сделать это - read -r -p 'input: ' && printf '%q\n' "$REPLY"предоставить данные при появлении запроса.
Патрик
1
Как я уже говорил несколько раз. Не знать, как передать необработанные данные в оболочку, не проблема printf. Возможно, вам следует задать вопрос, а не критиковать решение, которое не имеет ничего общего с вашей проблемой.
Патрик
4

Пытаться:-

file=Dr\'\ A.tif
echo $file
Dr' A.tif

или

file="Dr' A.tif"
echo $file
Dr' A.tif

или если строка содержит двойные кавычки: -

file='Dr" A.tif'
echo $file
Dr" A.tif

Есть хорошие учебники по выходу и цитированию в сети. Начни с этого .

garethTheRed
источник
1

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

Поскольку вы перебираете выходные данные find, это один из самых простых способов (!) Для обработки всех возможных путей :

while IFS= read -r -d ''
do
    file_namex="$(basename -- "$REPLY"; echo x)"
    file_name="${file_namex%$'\nx'}"
    do_something -- "$file_name"
done <(find "$some_path" -exec printf '%s\0' {} +)
l0b0
источник
0

быстро и (очень) грязно

find . | sed 's/^/"/' | sed 's/$/"/'
Майкл
источник
-1

Многие из этих ответов, в том числе пользующиеся наибольшим количеством голосов, не printf "%q"будут работать во всех случаях без дополнительных манипуляций. Я хотел бы предложить следующее (пример ниже):

cat <<EOF; 2015-11-07T03:34:41Z app[postgres.0000]: [TAG] text-search query doesn't contain lexemes: "" EOF

user3467349
источник
Извините за вопрос n00b, но не могли бы вы уточнить, как бы вы на самом деле использовали это для экранирования символов в строке? Если я копирую код, который вы пишете, в мой терминал, он просто печатает приложение 2015-11-07T03: 34: 41Z [postgres.0000]: [TAG] запрос текстового поиска не содержит лексем: "" ... ничего не экранируется ,
SharkAlley
Это буквально точка, все специальные символы будут интерпретироваться как буквенные символы не для их особого смысла. Вместо этого попробуйте повторить «приведенную выше строку», чтобы увидеть разницу.
user3467349