我有一个传递几个文件名作为参数的函数。某些文件名可能会引用不存在或已被删除的文件。因为args中可能还存在目录,所以我想获得以args形式传递的所有文件以及可能包含在args中的目录中包含的所有文件的递归列表。
function SomeFunction () {
# get list of files recursively
fList=$(find $@ -type f)
do something with $fList
.
.
.
}
[~]$SomeFunction existentFile nonexistentFile existentNonEmptyDir
find: `nonexistentFile': No such file or directory
fList=$(find $@ -type f)
如果不是nonexistentFile
会很好用。即使文件丢失,有没有办法进行相同的呼叫?
答案 0 :(得分:3)
忽略find
发出的警告是完全合理的。但是,如果要过滤参数列表以查找在调用之前实际存在的事物,则可以明确地做到这一点:
SomeFunction() {
local -a existing_args=( )
for arg in "$@"; do
[[ -e "$arg" ]] && existing_args+=( "$arg" )
done
while IFS= read -r -d '' result; do
printf 'Processing result: %q\n' ## put your own code here
done < <(find "${existing_args[@]}" -type f -print0)
}
一些注意事项:
function
关键字取自function SomeFunction {
的ksh函数声明语法;函数名称后面的括号来自SomeFunction() {
的POSIX sh函数声明语法。将它们两者组合在一起的结果既不兼容旧的ksh也不兼容POSIX sh。参见http://wiki.bash-hackers.org/scripting/obsolete "$@"
可确保正确处理包含空格,全局字符等的文件名;同样在数组扩展中,例如"${existing_args[@]}"
。existing_args
被定义为一个数组-字符串列表-而不是单个字符串。这很重要,因为文件名本身就是字符串,并且尝试遍历字符串就好像它是列表一样通常是有问题的(再次影响文件中名称中包含空格,原义换行符,glob字符等)。find -print0
可确保我们使用NUL分隔文件名。这很重要,因为UNIX中的文件名在内部作为NUL分隔的字符串传递。因此,NUL是保证路径中不存在的唯一字符。 IFS= read -r -d '' var
从这样一个以NUL分隔的字符串中读取一个条目。< <(...)
可确保我们将...
的输出重定向到该重定向的循环,同时放置find
而不是循环–在一个子shell中。有关为何如此重要的示例,请参见BashFAQ #24。答案 1 :(得分:1)
someFunction () {
# remove nonexistent names from argument list
for pathname do
[ -e "$pathname" ] && set -- "$@" "$pathname"
shift
done
# exit with failure if none of the given pathnames existed
[ "$#" -eq 0 ] && return 1
# find regular files in the given existing paths and process these
find "$@" -type f -exec sh -c '
for pathname do
# process found regular file "$pathname"
done' sh {} +
}
$@
,否则shell将对元素进行单词拆分和文件名遍历。find
的输出保存到字符串中。如果任何文件名包含空格,那将会中断。