对于路径下的每个目录,从该目录执行shell脚本(当find -execdir不合适时)

对于路径下的每个目录,从该目录执行shell脚本(当find -execdir不合适时)

我有一个现有的 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/stufffn_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_argsh -ccd

请注意,$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+findsh -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)

编辑:响应评论,此解决方案不适用于相对路径。

相关内容