bash 循环脚本中的多个元素而不是一个

Multiple elements instead of one in bash script for loop

我一直在关注这些问题中给出的答案

Shellscript Looping Through All Files in a Folder

How to iterate over files in a directory with Bash?

编写一个 bash 脚本,遍历文件夹中的文件并处理它们。所以,这是我的代码:

#!/bin/bash

YEAR="2002/"
INFOLDER="/local/data/datasets/Convergence/"

for f in "$INFOLDER$YEAR*.mdb";
do
    echo $f
    absname=$INFOLDER$YEAR$(basename $f)

    # ... the rest of the script ...

done

我收到这个错误:basename: extra operand.

我添加了 echo $f,我意识到 f 包含 所有文件名,由 space 分隔。但我希望一次得到一个。这可能是什么问题?

只要引用您的 shell 变量,如果它们 应该 包含中间有空格的字符串。

basename "$f"

不这样做会导致将字符串拆分为单独的字符 (see WordSplitting in bash),从而弄乱需要一个字符串参数而不是多个字符串参数的 basename 命令。

此外,将 * 包含在双引号之外是明智的,因为 shell 通配在它们内部不起作用(单引号或双引号)。

#!/bin/bash

# good practice to lower-case variable names to distinguish them from
# shell environment variables

year="2002/"
in_folder="/local/data/datasets/Convergence/"

for file in "${in_folder}${year}"*.mdb; do
    # break the loop gracefully if no files are found
    [ -e "$file" ] || continue 
    echo "$file"
    # Worth noting here, the $file returns the name of the file
    # with absolute path just as below. You don't need to 
    # construct in manually
    absname=${in_folder}${year}$(basename "$file")
done

只需从这一行中删除“” 对于“$INFOLDER$YEAR*.mdb”中的 f;

看起来像这样

#!/bin/bash

YEAR="2002/"
INFOLDER="/local/data/datasets/Convergence/"

for f in $INFOLDER$YEAR*.mdb;
do
    echo $f
    absname=$INFOLDER$YEAR$(basename $f)

    # ... the rest of the script ...

done

您 运行 遇到了引用问题。在shell中,双引号防止分词和通配符扩展;通常,您不希望这些事情发生在变量的值上,因此您应该对变量引用加双引号。但是当你有一些东西 应该 分词或通配符扩展时,它 不能 被双引号。在您的 for 语句中,您将整个文件模式用双引号引起来:

for f in "$INFOLDER$YEAR*.mdb";

...这可以防止对变量值进行分词和通配符扩展(好),但也可以防止它在 * 上,您 需要 扩展(这就是循环的重点)。所以需要有选择地引用,变量在引号内,通配符在引号外:

for f in "$INFOLDER$YEAR"*.mdb;

然后在循环内,您应该双引号引用 $f 以防任何文件名包含空格或通配符(这在文件名中是完全合法的):

echo "$f"
absname="$INFOLDER$YEAR$(basename "$f")"

(注意:实际上不需要 absname 赋值周围的双引号——赋值的右侧是 shell 中为数不多的安​​全位置之一跳过它们——但在我看来,将所有变量引用和 $( ) 表达式加双引号比试图跟踪安全和不安全的地方更容易和更安全。)