Bash glob参数仅显示第一个文件而不是所有文件

时间:2015-04-04 22:25:36

标签: bash shell glob

我想运行此cmd行脚本

$ script.sh   lib/* ../test_git_thing

我希望它能处理/ lib文件夹中的所有文件。

FILES=$1
for f in $FILES
do
  echo "Processing $f file..."
done

目前它只打印第一个文件。如果我使用$ @,它会给我所有文件,但也是我不想要的最后一个参数。有什么想法吗?

4 个答案:

答案 0 :(得分:2)

正如所指出的那样,命令行上的lib/*正在扩展为lib中的所有文件。为防止扩展,您有2个选项。 (1)引用你的意见:

$ script.sh 'lib/*' ../test_git_thing

或(2),关闭文件全局。但是,选项set -f将禁用shell中的路径名扩展,但它将禁用所有路径名扩展(在将参数传递给脚本之前,在shell中进行扩展时,在脚本中设置它并不会有帮助) 。在您的情况下,最好引用输入或将第一个参数作为目录名传递,并在脚本中添加扩展:

DIR=$1
for f in "$DIR"/*

答案 1 :(得分:1)

当您调用“script.sh lib / *”时,在命令行中展开参数列表,并使用lib / as args中的所有文件调用您的脚本。由于您只在脚本中引用$ 1,因此它只打印第一个文件。您需要在命令行中转义通配符,以便将其传递给您的脚本以执行通配。

答案 2 :(得分:1)

在bash和ksh中,你可以遍历除了最后一个之外的所有参数:

for f in "${@:1:$#-1}"; do
  echo "$f"
done

在zsh中,你可以做类似的事情:

for f in $@[1,${#}-1]; do
  echo "$f"
done

$#是参数的数量,${@:start:length}是bash和ksh中的子字符串/子序列表示法,而$@[start,end]是zsh中的子序列。在所有情况下,下标表达式都被计算为算术表达式,这就是$#-1工作的原因。 (在zsh中,您需要${#}-1,因为$#-被解释为" $-"的长度。)

在所有三个shell中,您可以使用带有标量变量的${x:start:length}语法来提取子字符串;在bash和ksh中,您可以将${a[@]:start:length}与数组一起使用来提取值的子序列。

答案 3 :(得分:0)

这回答了给定的问题,没有使用非POSIX功能,也没有解决方法,例如禁用globbing。

您可以使用循环找到最后一个参数,然后在处理文件列表时将其排除。在此示例中,$d是目录名称,而$f与原始答案中的含义相同:

#!/bin/sh
if [ $# != 0 ]
then
        for d in "$@"; do :; done
        if [ -d "$d" ]
        then
                for f in "$@"
                do
                        if [ "x$f" != "x$d" ]
                        then
                                echo "Processing $f file..."
                        fi
                done
        fi
fi

此外,最好还测试"$f"是否是一个文件,因为如果找不到匹配项,shell通常会通过参数列表传递通配符。