为什么 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 扩展 - 包含 *
的字符串需要作为文字传递给每个 echo
和 find
命令。所以 $i
应该用双引号括起来——这将允许从 $i
扩展变量,但不会发生后续的通配符扩展。 (如果使用单引号,即 '$i'
,那么文字 $i
将被传递给 echo
和 find
,这也是不需要的。)
除此之外,如果当前目录中存在与任何 glob 模式匹配的任何文件,初始 for
行需要使用引号来防止通配符扩展。这里不管用单引号还是双引号。
另外,这里修改后的代码也删除了一些不必要的分号。 bash 中的分号是命令分隔符,不需要仅仅用于终止语句(如在 C 等中)。
使用原始代码观察到的行为
这里似乎发生的是初始 for
语句中使用的模式之一是匹配当前目录中的文件(具体来说 *.sh
匹配 file1.sh
file2.sh
,和 file3.sh
)。因此,它被表达式中这些文件名的列表 (file1.sh file2.sh file3.sh
) 替换,并且 for
语句将迭代这些值。 (请注意,当前目录可能与脚本所在的位置或用于 find
的顶级目录不同。)
还预计表达式中将使用 *.pdf
和 *.txt
-- 替换与否,取决于是否找到任何匹配项。因此问题中显示的输出可能不是脚本的整个输出。
我想在图片文件夹中找到一些文件类型,我在 /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 扩展 - 包含 *
的字符串需要作为文字传递给每个 echo
和 find
命令。所以 $i
应该用双引号括起来——这将允许从 $i
扩展变量,但不会发生后续的通配符扩展。 (如果使用单引号,即 '$i'
,那么文字 $i
将被传递给 echo
和 find
,这也是不需要的。)
除此之外,如果当前目录中存在与任何 glob 模式匹配的任何文件,初始 for
行需要使用引号来防止通配符扩展。这里不管用单引号还是双引号。
另外,这里修改后的代码也删除了一些不必要的分号。 bash 中的分号是命令分隔符,不需要仅仅用于终止语句(如在 C 等中)。
使用原始代码观察到的行为
这里似乎发生的是初始 for
语句中使用的模式之一是匹配当前目录中的文件(具体来说 *.sh
匹配 file1.sh
file2.sh
,和 file3.sh
)。因此,它被表达式中这些文件名的列表 (file1.sh file2.sh file3.sh
) 替换,并且 for
语句将迭代这些值。 (请注意,当前目录可能与脚本所在的位置或用于 find
的顶级目录不同。)
还预计表达式中将使用 *.pdf
和 *.txt
-- 替换与否,取决于是否找到任何匹配项。因此问题中显示的输出可能不是脚本的整个输出。