パスの下の各ディレクトリに対して、そのディレクトリでシェルスクリプトを実行します(find -execdirが適切でない場合)。

パスの下の各ディレクトリに対して、そのディレクトリでシェルスクリプトを実行します(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/stuffとを変更しますfn_parameter。私も時々変更が必要ですfunction_name

このコマンドを再入力するのは面倒なので、他のスクリプトでラップして、次の3つのパラメータだけを渡したいと思います。

wrapper.sh function_name "/path/to/my/stuff" fn_parameter

注:「function_name」が最も頻繁に変更されない項目であるため、パラメーターの順序を変更しました。

このラッパースクリプトを作成しようとすると、引用とエスケープに圧倒されます。 shellcheck.netでスクリプトを見て配列を試しましたがcmd(以下で失敗した試みの1つを参照)、成功しませんでした。引用符とバックスラッシュが尊重されないことが問題である可能性が高いことはわかっていますが、この問題を解決する方法を理解できません。

これは私が失敗した多くの試みの一つです。

ラッパー.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

コードの2つのバリエーションは、それぞれ呼び出すインラインスクリプトに特別な値を渡します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" {} \;

ディレクトリを見つけたら、両方の変数の値をディレクトリパスパラメータの前の2番目の引数としてfind スクリプトに渡すだけです。fn_nameスクリプト内で、最初の2つのパラメータをスクリプトのパラメータとして使用し、3番目のパラメータをディレクトリパスとして使用します。fn_argsh -ccd

文字列が$0含まれますsh。シェルは、生成される可能性のあるすべてのエラーメッセージにこの(任意の)文字列を使用します(質問に例を示しました)。その$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" {} +

\;コマンドの最後でに変更して、次のように呼び出します。+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

cdスクリプトを実行するたびに「返す」必要がないように、サブシェルでループ本体を実行します。

このコードの実行に欠陥がないshため、ここで代わりに使用しています。また、ここに示すコマンドは標準機能のみを使用します。bashshfind

おすすめ記事