使用glob在for循环中指定“ ./”有什么好处吗?


10

我的印象是./*.fastq,搜索以结尾的文件时可能更安全.fastq。例如,./将阻止捕获文件.fastq。显然这是错误的,如下例所示:

TMP_DIR=$(mktemp --directory)
mkdir -p ${TMP_DIR}
(cd ${TMP_DIR}
 touch {a,b,c,}.fastq
 ls -a
 echo ""

 echo "# match all:"
 for f in *.fastq ; do
     echo "${f}"
 done
 echo ""

 echo "# with ./:"
 for f in ./*.fastq ; do
     echo "${f}"
 done
)
rm -rf ${TMP_DIR}
.
..
a.fastq
b.fastq
c.fastq
.fastq

# match all:
a.fastq
b.fastq
c.fastq

# with ./:
./a.fastq
./b.fastq
./c.fastq

既不*.fastq也不./*.fastq匹配文件.fastq。所以我现在想知道,./*.fastq这里是否有任何用处,或者./*总的来说?


1
通常要指出的./*是,它确保开头的名称-不被视为选项。
查尔斯·达菲,

Answers:


15

最初,这是令人惊讶的通配符行为,因为对*通配符的描述是:

匹配任何字符串,包括空字符串。

...直到您意识到该时间段是文件名的第一个字符时才有点特殊。中的介绍性文字3.5.8 Filename Expansion说:

当使用模式扩展文件名时,字符“。” 除非设置了shell选项dotglob,否则必须显式地匹配文件名开头或紧跟斜杠之后的内容。

正如steeldriver所说,在通配符前面加上前缀的“使用模式” ./对于在bash shell中处理带引号的名称很有。它对通配符/文件名扩展没有影响,但是,如果它们以那些程序可能会误解为选项的字符开头,则在引用它们时更安全/更轻松地处理文件名。例如:

# I want a file named `-n`
$ touch -n
touch: invalid option -- 'n'
Try 'touch --help' for more information.
$ touch -- -n
### ok
$ touch ./-n
### ok

...并且现在我一个名为的文件-n,如果我碰巧用通配符对其进行循环:

for file in *n
do
  echo "$file"
done

...我没有输出!

但是,如果我在通配符前面加上./

for file in ./*n
do
  echo "$file"
done
./-n

...我看到文件名。

这是一个简单的示例,用于演示;另请参见为什么printf比echo好?为此和其他原因。其他实用程序将被其他选项绊倒,因此最好将文件名尽可能安全地呈现给这些实用程序。如果您没有在通配符前添加“转义”文件名,则必须以其他方式“保护”实用程序。一种常见的方法是用来表示选项的结束--,例如:

for file in *n
do
  mv -- "$file" backup/"$file"
done

...会将-n文件名安全地传递到mv(如下方所示set -x):

mv -- -n backup/-n
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.