我制作的 bash 脚本遇到问题。在 for 循环中,我迭代所有参数来构造一个字符串变量,该变量稍后将输入到“eval”命令:
for arg in "$*"
do
if [ $arg != $lastArg ]; then
findTarget+="-name $arg -o "
else
findTarget=$(echo $findTarget | sed 's/-o$//')
break
fi
done
问题源于“$*”。例如,当我在参数中输入“*.c”,并且当前文件夹包含与该模式匹配的文件时,参数*.c
将扩展为这些文件;我不希望那样,我想findTarget
与 相连-name *.c -o
,我尝试过使用 eval 并没有引号,似乎没有任何效果。知道如何做到这一点(如果可能的话,简单地)?注意:参数总数可能会有所不同。
这是我如何运行脚本的示例:
$ trouver.bash *.c *.f90 someString
在我的 for 循环结束时,变量findTarget
应该读取-name *.c -o -name *.f90
*.c
如果或*.f90
匹配当前文件夹中的文件,则此操作不起作用...
答案1
循环位置参数的语法是for arg do
单独的。"$*"
是位置参数与第一个字符的串联$IFS
,因此您将仅循环一个元素。
另外,如果您想为命令构建参数列表find
,则需要一个数组,而不是字符串。并且不要忘记引用您的变量!
所以:
findTarget=()
or=()
for arg
do
[ "$arg" = "$lastArg" ] && break
findTarget+=("${or[@]}" -name "$arg")
or=(-o)
done
find . \( "${findTarget[@]}" \)
请注意,当您调用脚本时,您需要引用...模式*.c
,否则它们将在传递给脚本之前由 shell 扩展。
trouver.bash '*.c' '*.f90' someString
如果您的交互式 shell 是zsh
,您可以为禁用通配符的命令定义一个别名:
alias trouver.bash='noglob trouver.bash'
这样,您可以执行以下操作:
trouver.bash *.c *.f90 someString
没有外壳扩展这些*.c
*.f90
球体。
答案2
使用"$*"
方法将所有参数连接成一个长参数。将其更改为"$@"
应该给出参数列表。但没有真正需要使用for arg in "$@"
正确for arg
的习语。
-o
然后,为每个新参数添加一个,我们可以使用${findTarget[@]+"-o "}
.
如果没有分配任何值,则它将为 null;如果分配了任何值,findTarget
则它将是纯字符串。在第一次循环运行中,它将崩溃为空,在下一次循环中,它将变成。-o
findTarget
-o
(( $# < 1 )) && echo "please provide some argument(s)" && exit 1
unset findTarget
for arg
do [[ "$arg" == "$lastArg" ]] && break
findTarget+=("${findTarget[@]+"-o "}-name $arg")
done
find . \( "${findTarget[@]}" \)
您需要记住按如下方式运行脚本:
$ trouver.bash '*.c' '*.f90' someString
如您所愿,每个参数都不会被 shell 扩展(使用单引号。双引号可能有效,但不能清楚地表达保留参数而不扩展的意图)。
如果您需要使用不带“单引号”的脚本,您可以删除“路径名扩展”(set -f)以避免扩展*
.
$ ( set -f; trouver.bash *.c *.f90 someString )
这()
将避免对 noglob 的更改影响当前正在运行的 shell。
这是可行的,因为脚本会将结果写入stdout
,它也可以从子 shell 内部进行打印(…)
。