我有以下目录结构,我正在尝试创建一个简单的bash脚本,用模式foo*/scripts/*A.txt打印出所有文件(即foo1/scripts/fileA.txt和foo2/scripts/fileA.txt)
$ tree
.
??? bar
? ??? scripts
? ??? fileA.txt
? ??? fileB.txt
??? bash_scrap.sh
??? foo1
? ??? scripts
? ??? fileA.txt
? ??? fileB.txt
??? foo2
??? scripts
??? fileA.txt
??? fileB.txt
Run Code Online (Sandbox Code Playgroud)
我现在创建一个脚本bash_scrap.sh,我想用第一个命令行参数给出的模式打印所有文件名.
$ cat bash_scrap.sh
#!/bin/bash
FILES=$1
for f in $FILES
do
echo "Processing $f file..."
printf "\n\n"
done
Run Code Online (Sandbox Code Playgroud)
当我直接定义FILES并在终端中运行脚本时,我得到了预期的输出
$ FILES=foo*/scripts/*A.txt
$ for f in $FILES; do echo "Processing $f file..."; printf "\n\n"; done
Processing foo1/scripts/fileA.txt file...
Processing foo2/scripts/fileA.txt file...
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试将此作为带有输入模式的脚本运行,它只打印出第一个文件名.
$ ./bash_scrap.sh foo*/scripts/*A.txt
Processing foo1/scripts/fileA.txt file...
Run Code Online (Sandbox Code Playgroud)
这是为什么?
$ ./bash_scrap.sh foo*/scripts/*A.txt
Run Code Online (Sandbox Code Playgroud)
......不把foo*/scripts/*A.txt在$1.相反,它扩展 foo*/scripts/*A.txt,并将第一个结果放入$1,第二个结果$2,等等.这发生在脚本启动之前(由调用shell执行,而不是运行脚本),所以你无法避免它通过修改脚本的文本.
如果您希望将glob作为文字值传递给脚本并仅在该脚本启动后进行解释,则需要引用它:
$ ./bash_scrap.sh 'foo*/scripts/*A.txt'
Run Code Online (Sandbox Code Playgroud)
但是,更好的方法是期望父shell为您进行扩展,并迭代"$@":
for f do
echo "Processing $f file"
done
Run Code Online (Sandbox Code Playgroud)
这就是程序之类的ls工作方式:运行时ls *.txt,用户的shell会在启动之前替换*.txt为匹配文件列表.预计不会给予水珠,如果您无法正常工作做给它一个(尝试运行,你会看到它总是给一个文件未找到错误,除非你已经创建了一个文件与字面名称).lslsls '*.txt'