bash 迭代文件列表,除非为空

bash 迭代文件列表,除非为空

我以为这很简单 - 但事实证明它比我预期的要复杂。

我想遍历目录中特定类型的所有文件,所以我这样写:

#!/bin/bash

for fname in *.zip ; do
   echo current file is ${fname}
done

这有效只要至少有一个匹配的文件在目录中。但是,如果没有匹配的文件,我会得到以下信息:

current file is *.zip

然后我尝试:

#!/bin/bash

FILES=`ls *.zip`
for fname in "${FILES}" ; do
    echo current file is ${fname}
done

虽然没有文件时循环体不会执行,但我从 ls 收到错误:

ls: *.zip: No such file or directory

如何编写一个循环来干净地处理不匹配的文件?

答案1

在 中bash,您可以设置该nullglob选项,以便不匹配任何内容的模式“消失”,而不是被视为文字字符串:

shopt -s nullglob
for fname in *.zip ; do
   echo "current file is ${fname}"
done

在 POSIX shell 脚本中,您只需验证是否fname存在(同时使用[ -f ],检查它是常规文件(或常规文件的符号链接),而不是其他类型,如目录/fifo/设备...):

for fname in *.zip; do
    [ -f "$fname" ] || continue
    printf '%s\n' "current file is $fname"
done

如果要循环遍历名称以任何类型结尾的所有(非隐藏)文件,请替换[ -f "$fname" ]为。[ -e "$fname" ] || [ -L "$fname ].zip

如果您还想考虑名称以*.zip..*.zip .zip *.zip.zip

答案2

set ./*                               #set the arg array to glob results
${2+":"} [ -e "$1" ] &&               #if more than one result skip the stat "$1"
printf "current file is %s\n" "$@"    #print the whole array at once

###or###

${2+":"} [ -e "$1" ] &&               #same kind of test
for    fname                          #iterate singly on $fname var for array
do     printf "file is %s\n" "$fname" #print each $fname for each iteration
done                                  

在此处的评论中,您提到调用一个函数......

file_fn()
    if     [ -e "$1" ] ||               #check if first argument exists
           [ -L "$1" ]                  #or else if it is at least a broken link
    then   for  f                       #if so iterate on "$f"
           do : something w/ "$f"
           done
    else   command <"${1-/dev/null}"    #only fail w/ error if at least one arg
    fi

 file_fn *

答案3

使用查找

export -f myshellfunc
find . -mindepth 1 -maxdepth 1 -type f -name '*.zip' -exec bash -c 'myshellfunc "$0"' {} \;

您必须导出您的 shell 函数才能export -f使其工作。现在find执行bash它执行您的 shell 函数,并仅保留在当前目录级别。

答案4

代替:

FILES=`ls *.zip`

尝试:

FILES=`ls * | grep *.zip`

这样,如果 ls 失败(在您的情况下),它将 grep 失败的输出并作为空白变量返回。

current file is      <---Blank Here

您可以添加一些逻辑以使其返回“未找到文件”

#!/bin/bash

FILES=`ls * | grep *.zip`
if [[ $? == "0" ]]; then
    for fname in "$FILES" ; do
        echo current file is $fname
    done
else
    echo "No Files Found"
fi

这样,如果上一个命令成功(以 0 值退出),那么它将打印当前文件,否则它将打印“No Files Found”

相关内容