如何转义字符串中的特殊字符?


16

假设$file拥有文件名的值,请说Dr' A.tif。在bash编程中,如何在$file不删除特殊字符的情况下转义单引号和其他任何特殊字符?

2014年7月9日更新

根据@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.tifprintf命令似乎无济于事,它会向我显示Dr\^s\ A.tif。如果我在这样的控制台上手动尝试:

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

我将得到以下输出:

Dr\\\^s\ A.tif

知道如何处理吗?


3
您希望在什么情况下使用$ file?还是将带有特殊字符的字符串分配给$ file的问题?
2014年

实际上,find命令返回一个文件列表数组。然后,我遍历此文件列表进入$ file变量。
huahsin68 2014年

2
您在此处已获得一些正确答案,但它们可能不是您真正提出的问题的答案。根据您在这里的评论,我强烈怀疑您走错了路。我们无法为您提供太多帮助,因为您一直没有显示代码。但是,我建议您阅读为什么我的shell脚本在空白或其他特殊字符上会阻塞?作为背景。显示您的脚本并解释您想做什么。
吉尔(Gilles)'所以

Answers:


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"。您首先需要了解参数解析在Shell中的工作方式。请参阅gnu.org/software/bash/manual/bash.html#Shell-Operation#2发生在#6之前。
Patrick

您能否提供一个印有该字符串printf且没有其他操作的示例It doesn't have a: ""
user3467349

您的问题与无关printf。您的问题是您不希望外壳程序解析您的字符串。为了做到这一点,您必须以甚至不尝试解析它的方式将输入传递给shell。一种方法是read -r -p 'input: ' && printf '%q\n' "$REPLY",并在出现提示时提供输入。
Patrick

1
正如我已经说过几次了。不知道如何将原始数据传递到Shell并不是问题printf。也许您应该问一个问题,而不是提出与您的问题无关的解决方案。
Patrick

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

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


请问n00b问题,但是您能否详细说明如何实际使用它来转义字符串中的字符?如果我将您编写的代码复制到我的终端中,它只会打印2015-11-07T03:34:41Z app [postgres.0000]:[TAG]文本搜索查询不包含词素:“” ...没有任何转义。
SharkAlley

从字面意义上讲,所有特殊字符都被解释为文字字符,并非出于其特殊含义。尝试回显 “上面的字符串”,以查看区别。
user3467349
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.