我有一个现有的 bash 脚本,如下所示:
find /path/to/my/stuff -type d -exec sh -c 'cd "$0"; /path/to/my/script.sh function_name fn_parameter' {} \;
我经常更改/path/to/my/stuff
和fn_parameter
。我有时也需要更改function_name
.
不断重新输入此命令变得很乏味,因此我想将其包装在另一个脚本中并仅传递这三个参数,如下所示:
wrapper.sh function_name "/path/to/my/stuff" fn_parameter
旁注:我更改了参数的顺序,因为“function_name”是更改最不频繁的一个。
当我尝试制作这个包装脚本时,我对引用和转义感到不知所措。我查看了 shellcheck.net 中的脚本,还尝试使用数组进行cmd
(请参阅下面我的失败尝试之一),但没有成功。我确实知道问题很可能是引号和反斜杠没有得到尊重,但我不明白如何解决这个问题。
这是我多次失败的尝试之一:
包装器.sh
#!/bin/bash
function_name=$1
mpath="$2"
arg=$3
find "$mpath" -type d -exec sh -c "cd \"$0\"; /path/to/my/script.sh $function_name $arg" {} \;
这是失败尝试的另一个例子:
#!/bin/bash
function_name=$1
mpath="$2"
arg=$3
cmd="'cd \$0; /path/to/my/script.sh $function_name $arg'"
echo "find \"$mpath\" -type d -exec sh -c $cmd {} \;"
find "$mpath" -type d -exec sh -c $cmd {} \;
在上面的示例中,如果我在命令行上输入 echo 语句的输出,它就会正常工作。但包装器失败并显示:
$0;: -c: line 1: unexpected EOF while looking for matching `''
$0;: -c: line 2: syntax error: unexpected end of file
为了完整起见,myscript.sh 与此类似:
#!/bin/bash
fn1() {
...
}
fn2() {
...
}
fn3() {
...
}
"$@"
答案1
代码的两个变体,每个变体将特殊值传递到您调用的内联脚本中find
:
#!/bin/sh
mpath=$1
fn_name=$2
fn_arg=$3
find "$mpath" -type d -exec sh -c '
cd "$3" && /path/to/my/script.sh "$1" "$2"' sh "$fn_name" "$fn_arg" {} \;
找到目录后,find
只需将两个变量的值传递到脚本中fn_name
,作为目录路径参数之前的两个第一个参数。在脚本内部,我们使用前两个参数作为脚本的参数,第三个参数作为into 的目录路径。fn_arg
sh -c
cd
请注意,$0
将包含字符串sh
。 shell 将在它可能产生的任何错误消息中使用此(任意)字符串(您在问题中显示了一个示例)。其$0
值为不是位置参数列表的一部分。
另一种变体是一次调用具有尽可能多的目录路径的内联脚本:
#!/bin/sh
mpath=$1
fn_name=$2
fn_arg=$3
find "$mpath" -type d -exec sh -c '
fn=$1 arg=$2; shift 2
for dirpath do
( cd "$dirpath" && /path/to/my/script.sh "$fn" "$arg" )
done' sh "$fn_name" "$fn_arg" {} +
通过在命令末尾更改\;
为,我们调用with+
find
sh -c
批次找到的目录路径。然后,内联脚本必须循环这些并依次调用每个脚本。
内联脚本首先从位置参数列表中挑选函数名称和参数,并将它们从该列表中移出。然后它循环遍历剩余的参数和调用cd
以及每个参数的脚本。以下是插入了一些额外空气的内联脚本:
fn=$1 # 1st argument from find
arg=$2 # 2nd argument from find
shift 2 # remove them from the list
# Iterate over the remaining arguments
for dirpath do
( cd "$dirpath" && /path/to/my/script.sh "$fn" "$arg" )
done
我在子 shell 中运行循环体,以避免cd
每次运行脚本后都必须“返回”。
我sh
在这里使用而不是因为运行此代码bash
没有任何缺陷。sh
此外,find
此处显示的命令仅使用标准功能。
答案2
这是我提出的(和工作的)解决方案:
#!/bin/bash
function_name=$1
mpath="$2"
marg=$3
while IFS= read -r -d '' sdir
do
cd "$sdir"
/path/to/my/script.sh "$function_name" "$marg"
done < <(find "$mpath" -type d -print0)
编辑:响应评论,此解决方案不适用于相对路径。