考虑拥有这些目录和文件:
$ tree /tmp/test
/tmp/test
├── dir
│ ├── file_normal
│ ├── file with "double quote
│ ├── file with 'single quote
│ ├── file with space
│ └── special!char
├── dir with space
│ ├── file_normal
│ ├── file with "double quote
│ ├── file with 'single quote
│ ├── file with space
│ └── special!char
├── file_normal
├── file with "double quote
├── file with 'single quote
├── file with space
└── special!char
ls
添加单引号或双引号仅在必要时。注意dir
并file_normal
没有引用。
$ ls -1 /tmp/test
dir
'dir with space'
file_normal
'file with "double quote'
"file with 'single quote"
'file with space'
'special!char'
ls
对单个文件执行相同的操作。
不必要时不要添加引号:
$ ls "file_normal"
file_normal
$ ( cd dir ; ls "$( realpath file_normal )" )
/tmp/test/dir/file_normal
仅在必要时添加引号:
$ ls "file with space"
'file with space'
$ ( cd 'dir with space' ; ls "$( realpath file_normal )" )
'/tmp/test/dir with space/file_normal'
通常不鼓励考虑ls
在 shell 脚本程序中使用。有没有内置的Linux程序可以实现相同的功能:仅在必要时才向文件路径添加单引号或双引号?
答案1
是的:ls
。只需使用它即可。与任何规则一样,“不要使用 ls”也会有有意义的例外情况。这是其中之一。首先你需要了解为什么ls
不鼓励使用:
- 它用于简单的 shell glob 完美完成工作的情况,并且通常比可以做得更好,
ls
因为 shell 会直接为您提供单独单词的路径,而无需解析 的ls
输出。 (当你看到类似for i in $(ls *.xyz)
而不是的东西时,这尤其令人恼火for i in *.xyz
。) - 当尝试获取额外信息和文件名时,可变的列大小使其
ls -l
难以解析。使用stat
或find
代替。 ls
?
可能会使输出中特殊字符的处理变得棘手(例如,某些字符被替换)。
在这种情况下:
- 你显然已经有相关的路径,所以你不会误用
ls
它来获取glob就足够的地方 - 您没有使用
ls -l
或尝试获取路径以外的任何信息 - 你想
ls
提供(但--quoting-style=shell-escape
具体)的特殊输出
所以,只需使用类似的东西:
quoted_path=$(ls -d --quoting-style=shell-escape <some-path>)
只是一定要明白这不是标准。最近版本的 GNU ls 可以做到这一点,但 busybox ls 没有(AFAICT),因此并非所有 Linux 系统都会有它。
您还可以使用GNU 统计对于同样的事情,使用%N
格式说明符:
%N
– 如果是符号链接,则引用文件名并取消引用(见下文)
[...]可以使用环境变量设置
“ ”格式。如果未设置该环境变量,则默认值为“ ”。%N
QUOTING_STYLE
shell-escape-always
所以:
quoted_path=$(QUOTING_STYLE=shell-escape stat -c %N <some-path>)
for 的引用样式stat
似乎与 for 相同ls
(我敢打赌它们在内部使用相同的函数)。在这种情况下,主要的区别似乎是符号链接处理:stat
如果您想按原样处理符号链接,则可能不是您想要使用的:
% QUOTING_STYLE=shell-escape stat -c %N bar$'\n'baz$'\t'xyz
'bar'$'\n''baz'$'\t''xyz' -> 'foo bar'
% ls --quoting-style=shell-escape bar$'\n'baz$'\t'xyz
'bar'$'\n''baz'$'\t''xyz'
其他选项:
- Bash 参数扩展使用
Q
引号运算符:${foo@Q}
将用引号打印变量的内容foo
(但它似乎总是添加一些引号) - Bash 的
printf
格式%q
说明符(虽然它似乎优先使用反斜杠而不是引号,但如果不需要则不会添加转义)