为什么 echo 命令解释基本目录的变量?

Why does echo command interpret variable for base directory?

我想在图片文件夹中找到一些文件类型,我在 /home/user/pictures 文件夹中创建了以下 bash-脚本:

for i in *.pdf *.sh *.txt;
do
  echo 'all file types with extension' $i;
  find /home/user/pictures -type f -iname $i; 
done

但是当我执行 bash-脚本时,对于位于 基本目录 /home/user/pictures 的文件,它无法按预期工作。该命令不是 echo 'All File types with Extension *.sh' 而是解释基本目录的变量:

all file types with extension file1.sh
/home/user/pictures/file1.sh
all file types with extension file2.sh
/home/user/pictures/file2.sh
all file types with extension file3.sh
/home/user/pictures/file3.sh

我想知道为什么 echo - 命令不打印 "All File types with Extension *.sh"。

此类表达式 (*.blabla) 会在循环中更改 $i 的值。这是我会做的技巧:

for i in pdf sh txt;
do
  echo 'all file types with extension *.'$i;
  find /home/user/pictures -type f -iname '*.'$i; 
done

修改后的代码:

for i in '*.pdf' '*.sh' '*.txt'
do
    echo "all file types with extension $i"
    find /home/user/pictures -type f -iname "$i"
done

解释:

在 bash 中,包含 * 的字符串或扩展为此类字符串的变量可能会扩展为 glob 模式,除非该字符串通过将其放在内部来防止 glob 扩展引号(尽管如果 glob 模式不匹配任何文件,那么原始 glob 模式将在尝试扩展后保留)。

在这种情况下,不希望发生 glob 扩展 - 包含 * 的字符串需要作为文字传递给每个 echofind 命令。所以 $i 应该用双引号括起来——这将允许从 $i 扩展变量,但不会发生后续的通配符扩展。 (如果使用单引号,即 '$i',那么文字 $i 将被传递给 echofind,这也是不需要的。)

除此之外,如果当前目录中存在与任何 glob 模式匹配的任何文件,初始 for 行需要使用引号来防止通配符扩展。这里不管用单引号还是双引号。

另外,这里修改后的代码也删除了一些不必要的分号。 bash 中的分号是命令分隔符,不需要仅仅用于终止语句(如在 C 等中)。

使用原始代码观察到的行为

这里似乎发生的是初始 for 语句中使用的模式之一是匹配当前目录中的文件(具体来说 *.sh 匹配 file1.sh file2.sh,和 file3.sh)。因此,它被表达式中这些文件名的列表 (file1.sh file2.sh file3.sh) 替换,并且 for 语句将迭代这些值。 (请注意,当前目录可能与脚本所在的位置或用于 find 的顶级目录不同。)

还预计表达式中将使用 *.pdf*.txt -- 替换与否,取决于是否找到任何匹配项。因此问题中显示的输出可能不是脚本的整个输出。