3

コマンドの引数を変数に格納しています。私が欲しい最後のコマンドは次のとおりです。

mock -r myconfig --define "debug_package %{nil}" --resultdir results --rebuild mypackage.src.rpm

これが私の試みです:

set -x    # for debugging

RESULTDIR=results
MOCK_CONFIG="myconfig"
MOCK_ARGS="-r $MOCK_CONFIG --define \"debug_package %{nil}\" --resultdir $RESULTDIR"
cmd="mock $MOCK_ARGS --rebuild mypackage.src.rpm"
$cmd

結果は次のとおりです。

+ RESULTDIR=results
+ MOCK_CONFIG=myconfig
+ MOCK_ARGS='-r myconfig --define "debug_package %{nil}" --resultdir results'
+ cmd='mock -r myconfig --define "debug_package %{nil}" --resultdir results --rebuild mypackage.src.rpm'
+ mock -r myconfig --define '"debug_package' '%{nil}"' --resultdir results --rebuild mypackage.src.rpm
ERROR: Bad option for '--define' ("debug_package).  Use --define 'macro expr'

ご覧のとおり、--defineパラメーターの引数が正しく引用されていません。--define私はそれだけを渡していると思いdebug_packageますが、これは不完全です。

MOCK_ARGSの間のスペースをエスケープしようとしても、を定義するときに引用符のさまざまなバリエーションを試しました。debug_package%{nil}

引用符やエスケープのどの組み合わせで、この引数リストを作成し、このスクリプトからコマンドを実行できますか?

編集:

結果のコマンドを変数に格納する理由は、ログを記録してからコマンドを実行する関数に渡されるためです。

また、変数の代わりに配列を使用する必要があることを示唆するこのFAQに出くわしました。私はアレイの実験を始めましたが、今のところ実用的な解決策はありません。

4

2 に答える 2

4

シェルスクリプトは悲惨なものになる可能性があります。多くの場合、 cmd="blah $blah";$cmdとは異なりblah $blahます。eval $cmd$cmdの代わりに試すことができます。

モックの代わりにこのperlスクリプトを呼び出してみてください。

#!/usr/bin/perl
print join("\n",@ARGV),"\n";

引数リストが実際に何であるかを見て驚くかもしれません:

-r
myconfig
--define
"debug_package
%{nil}"
--resultdir
results
--rebuild
mypackage.src.rpm

「set-x」出力はこれを一重引用符で表示しようとしていると思いますが。

私が最近学んだ素晴らしいトリックの1つは、

function f {
  echo "$@"
}

実際には、位置引数をfに適切に転送します(転送$*しません)。

「eval」はおそらくあなたが意図したものを与えるように見えます:

set -x    # for debugging
RESULTDIR=results
MOCK_CONFIG="myconfig"
MOCK_ARGS="-r $MOCK_CONFIG "'--define "debug_package %{nil}" --resultdir '"$RESULTDIR"
cmd="mock $MOCK_ARGS --rebuild mypackage.src.rpm"
echo $cmd
eval $cmd

出力:

+ echo mock -r myconfig --define '"debug_package' '%{nil}"' --resultdir results --rebuild mypackage.src.rpm
mock -r myconfig --define "debug_package %{nil}" --resultdir results --rebuild mypackage.src.rpm
+ eval mock -r myconfig --define '"debug_package' '%{nil}"' --resultdir results --rebuild mypackage.src.rpm
++ mock -r myconfig --define 'debug_package %{nil}' --resultdir results --rebuild mypackage.src.rpm
-r
myconfig
--define
debug_package %{nil}
--resultdir
results
--rebuild
mypackage.src.rpm
于 2009-09-04T06:52:48.017 に答える
4

配列は、このようなことを行うための方法です。これが私が思いついたものです:

log_and_run() {
    echo "$(date): running command: $*"
    "$@"
    echo "$1 completed with status $?"
}

RESULTDIR=results
MOCK_CONFIG="myconfig"
MOCK_ARGS=(-r "$MOCK_CONFIG" --define "debug_package %{nil}" --resultdir "$RESULTDIR")
cmd=(mock "${MOCK_ARGS[@]}" --rebuild mypackage.src.rpm)
log_and_run "${cmd[@]}"
# could also use: log_and_run mock "${MOCK_ARGS[@]}" --rebuild mypackage.src.rpm

$ *は、スペースで区切られたすべてのパラメーターに展開されることに注意してください(ログコマンドに渡すのに適しています)。「$@」はすべてのパラメーターに個別の単語として展開されます(log_and_runで使用されているように、最初のコマンドは実行するコマンドとして扱われ、残りはパラメーターとして扱われます)。同様に、「$ {MOCK_ARGS [@]}」は、スペースが含まれているかどうかに関係なく、MOCK_ARGSのすべての要素に個別の単語として展開されます(したがって、MOCK_ARGSの各要素は、引用符解析の混乱なしにcmdの要素になります)。

また、MOCK_CONFIGとRESULTDIRの拡張を引用しました。スペースが含まれていないため、ここでは必要ありませんが、スペースが含まれている場合に備えて、これを取り入れることをお勧めします(たとえば、外部からスクリプトに渡される場合は、スペースが含まれている可能性があると想定する必要があります)。 。

ところで、関数に追加のパラメーターを渡す必要がある場合(ログに記録するファイル名の例を使用します)、配列スライシングを使用して、ログ/実行するコマンドとして使用する後のパラメーターのみを分割できます。

log_and_run() {
    echo "$(date): running command ${*:2}" >>"$1" 
    "${@:2}"
    echo "$2 completed with status $?" >>"$1"
}
#...
log_and_run test.log "${cmd[@]}"

補遺:ログ内のスペースを含むパラメーターを引用する場合は、「手動で」ログ文字列を作成し、必要な引用を行うことができます。例えば:

log_and_run() {
    local log_cmd=""
    for arg in "$@"; do
        if [[ "$arg" == *" "* || -z "$arg" ]]; then
            log_cmd="$log_cmd \"$arg\""
        else
            log_cmd="$log_cmd $arg"
        fi
    done
    echo "$(date): running command:$log_cmd"
    ...

これは、パラメーター内のスペースとブランクパラメーターを処理しますが、(たとえば)パラメーター内の二重引用符は処理しないことに注意してください。この「正しい」ことを行うと、任意に複雑になる可能性があります...

また、log_cmd文字列を作成する方法では、先頭にスペースが表示されます。上記では、echoコマンドでその前のスペースを省略して処理しました。実際にスペースをトリミングする必要がある場合は、を使用して"${log_cmd# }"ください。

于 2009-09-06T04:25:31.003 に答える