我需要查找目录中的所有内容,不包括某些子目录和文件。我的脚本需要将其作为函数调用:
function findStuff() {
# define exclusions
ignore_dirs=("$1" "*foo*") # exclude base dir
ignore_files=("one.txt" "two.txt" "*three*.txt")
# build patterns for find command
dir_pattern=""
file_pattern=""
for i in "${ignore_dirs[@]}"; do dir_pattern=$dir_pattern" ! -path \"$i\""; done
for i in "${ignore_files[@]}"; do file_pattern=$file_pattern" ! -name \"$i\""; done
# find
find "$1 $dir_pattern $file_pattern"
# now do other stuff with the results...
}
findStuff /some/base/dir
但这给了我一个No such file or directory
错误。
所以我想看看命令到底是什么,并尝试echo find "$1 $dir_pattern $file_pattern"
将其粘贴到命令行上,它起作用了。然后我将其粘贴到脚本中并运行它,它也起作用了!
所以我认为它失败是因为一些逃避问题。我做错了什么?
答案1
find
将使用它获取的第一个参数(直到第一个以-
or 开头的参数,即!
or (
)作为要搜索的顶级路径。find
当您在函数中调用它时,您将给出一个参数,即字符串$1 $dir_pattern $file_pattern
(变量已展开)。找不到该路径。
您还可以在您打算提供给 的参数中包含文字双引号find
。双引号的作用是防止 shell 扩展全局模式以及在空格(或变量IFS
包含的任何内容)上进行分割,但如果您使用例如,那么双引号将成为用于与文件名进行比较的! -name \"thing\"
模式的一部分。find
使用数组,并正确引用单独的参数find
:
myfind () {
local ignore_paths=( "$1" "*foo*" )
local ignore_names=( "one.txt" "two.txt" "*three*.txt" )
local path_args=()
for string in "${ignore_paths[@]}"; do
path_args+=( ! -path "$string" )
done
local name_args=()
for string in "${ignore_names[@]}"; do
name_args+=( ! -name "$string" )
done
find "$1" "${path_args[@]}" "${name_args[@]}"
}
每次我们追加到path_args
和name_args
上面时,我们都会向列表中添加三个元素:!
、-path
或-name
、 和"$string"
。当扩展"${path_args[@]}"
and "${name_args[@]}"
(注意双引号)时,元素将被单独引用。
等效实现适用于/bin/sh
:
myfind () (
topdir=$1
set --
# paths to ignore
for string in "$topdir" "*foo*"; do
set -- "$@" ! -path "$string"
done
# names to ignore
for string in "one.txt" "two.txt" "*three*.txt"; do
set -- "$@" ! -name "$string"
done
find "$topdir" "$@"
)
在sh
shell 中,我们只有一个可用的数组,它是位置参数列表,$@
因此我们find
在其中收集选项。显然,特定的解决方案bash
也可以编写为使用单个数组,并且sh
变体也会运行bash
。
最后,测试的输出echo
并不是函数执行的命令的准确表示。
考虑一下:
cat "my file name"
它运行cat
在名为 的东西上my file name
,并且
echo cat "my file name"
输出字符串cat my file name
.这是因为 shell 在执行命令之前删除了字符串周围的引号。跑步那命令,cat
会寻找三文件,没有一个。
当您将命令复制粘贴到 shell 中时,它运行良好,因为您在输出的字符串中包含了文字双引号echo
(通过转义它们),但这并不是您的函数执行的实际命令。