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


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

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


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

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


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' {} +)


-1

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

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


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

Это буквально точка, все специальные символы будут интерпретироваться как буквенные символы не для их особого смысла. Вместо этого попробуйте повторить «приведенную выше строку», чтобы увидеть разницу.
user3467349
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.