Rog*_*hin 3 bash quoting escape-characters subshell
当我执行以下命令时:
#!/bin/bash
while IFS= read -r -d '' file; do
files+=$file
done < <(find -type f -name '*.c' -print0)
echo "${files[@]}"
Run Code Online (Sandbox Code Playgroud)
我没有得到与此相同的结果:
#!/bin/bash
find_args="-type f '*.c' -print0"
while IFS= read -r -d '' file; do
files+=$file
done < <(find $find_args)
echo "${files[@]}"
Run Code Online (Sandbox Code Playgroud)
如何将第二个场景修复为与第一个相同?
我的理解是,因为双引号中有单引号,单引号会被转义,这会产生一个糟糕的扩展,看起来像这样:
find -type f -name ''\''*.c'\'' -print0
Run Code Online (Sandbox Code Playgroud)
BLayer 的答案是正确的,但要解构这里真正发生的事情(忽略缺少的-name
主要的错字):
#!/bin/bash
while IFS= read -r -d '' file; do
files+=$file
done < <(find -type f -name '*.c' -print0)
echo "${files[@]}"
Run Code Online (Sandbox Code Playgroud)
在进程替换( <(...)
)启动的shell中,bash解析如下命令:
find -type f -name '*.c' -print0
Run Code Online (Sandbox Code Playgroud)
因为水珠*.c
被引用,bash所做的没有展开。但是,单引号被删除了。所以当find
进程开始时,它看到的参数列表是:
-type
f
-name
*.c
-print0
Run Code Online (Sandbox Code Playgroud)
请注意,这些参数用空字节分隔,而不是用空格或换行符分隔。这是在 C 级别,而不是在 shell 级别。这与如何使用execve()
C执行程序有关。
现在对比一下,在以下代码段中:
#!/bin/bash
find_args="-type f -name '*.c' -print0"
while IFS= read -r -d '' file; do
files+=$file
done < <(find $find_args)
echo "${files[@]}"
Run Code Online (Sandbox Code Playgroud)
变量的值find_args
设置为:
-type f -name '*.c' -print0
Run Code Online (Sandbox Code Playgroud)
(双引号不是值的一部分,但单引号字符是。)
当命令find $find_args
运行时,根据man bash
,令牌$find_args
受到参数扩展,然后是分词,然后是路径名扩展(又名全局扩展)。
参数扩展后,您有-type f -name '*.c' -print0
. 请注意,这是在引用删除之后。所以单引号不会被删除。
分词后,您将以下内容作为单独的词:
-type
f
-name
'*.c'
-print0
Run Code Online (Sandbox Code Playgroud)
然后是路径名扩展。当然'*.c'
不太可能匹配任何你不一般把单引号中的文件名,所以其结果将可能是'*.c'
将作为文本模式传递find
,因此-name
主要将失败的所有文件。(仅当存在名称以单引号开头并以三个字符结尾的文件时才会成功.c'
)
编辑:实际上,如果有这样的文件,glob'*.c'
将扩展以匹配该文件和任何其他此类文件,然后扩展[实际文件名] 将find
作为模式传递给。 因此,是否-print0
会到达主要文件取决于 (a) 是否只有一个这样的文件名,以及 (b) 解释为 glob 的文件名是否与自身匹配。
例子:
如果您运行touch "'something.c'"
,则glob '*.c'
将扩展为'something.c'
,然后find
主-name 'something.c'
文件也将匹配该文件并打印出来。
如果你运行touch "'namewithcharset[a].c'"
,水珠'*.c'
会在外壳扩展至如此,但find
主要-name 'namewithcharset[a].c'
将不匹配自身,它只会匹配'namewithcharseta.c'
,不存在,那么-print0
将无法达成。
如果您运行touch "'x.c'" "'y.c'"
,glob'*.c'
将扩展为两个文件名,这将导致输出错误,find
因为'y.c'
它不是一个有效的主(并且它不能是因为它不以连字符开头)。
如果nullglob
设置了该选项,您将获得不同的行为。
也可以看看:
归档时间: |
|
查看次数: |
1868 次 |
最近记录: |