コマンドを動的に作成する


9

私はスクリプトで作業しており、tarコマンドを動的に作成する必要があります。

ここに私が何をしようとしているのかを説明する2つの例があります:

#!/bin/bash

TAR_ME="/tmp"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
_tar="tar "`printf -- '--exclude="%s" ' "${EXCLUDE[@]}"`" -zcf tmp.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

echo -e "\n\nNEXT:\n\n"

EXCLUDE=("--exclude=/tmp/hello\ hello" "--exclude=/tmp/systemd*" "--exclude=/tmp/Temp*")
_tar="tar "`printf -- '%s ' "${EXCLUDE[@]}"`" -zcf test.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

_tarコマンドとして使用できるようにしたいのですが、クラシックパスで機能させることができましたが、フォルダ名のスペースを操作する必要があります。そして、毎回次のようなエラーが発生しました:

COMMAND: tar --exclude="/tmp/hello hello" --exclude="/tmp/systemd*" --exclude="/tmp/Temp*"  -zcf tmp.tar.gz /tmp
tar: hello": Cannot stat: No such file or directory

COMMAND: tar --exclude=/tmp/hello\ hello --exclude=/tmp/systemd* --exclude=/tmp/Temp*  -zcf test.tar.gz 
tar: hello: Cannot stat: No such file or directory

知っておくべきことの1つだけです。非常に古いマシンでスクリプトを実行する必要があります。つまり、最後のbash機能を使用できません。


--excludeオプションはその後の単一の文字列のみを受け入れることができると思います。ただし、複数の--excludeステートメントを使用できます。「--exclude = / tmp / hello --exclude = hello」を試してみてください。気にしないで。誤解しました。
ルイスM

。@LewisM私は、OPは「を/ tmp /ハローハロー」(はい、スペースでディレクトリを除外したいと思います
Archemar

@ShellCodeすべての除外の引用についてはどうでしょうか。例: "--exclude = / tmp / hello hello"
Archemar

うん。そのため、後でOopsステートメントを記述します。:)
ルイスM

eval処刑の前に置くのはどうですか?
jimmij 2018年

回答:


11

実行可能な文字列を作成しようとしないでください。代わりに、配列に引数を作成し、呼び出し時にそれを使用しtarます(既にで配列を適切に使用していますEXCLUDE)。

#!/bin/bash

directory=/tmp

exclude=( "hello hello" "systemd*" "Temp*" )

# Now build the list of "--exclude" options from the exclude array:
for elem in "${exclude[@]}"; do
    exclude_opts+=( --exclude="$directory/$elem" )
done

# Run tar
tar -cz -f tmp.tar.gz "${exclude_opts[@]}" "$directory"

/bin/sh

#!/bin/sh

directory=/tmp

set -- "hello hello" "systemd*" "Temp*"

# Now build the list of "--exclude" options from the $@ array
# (overwriting the values in $@ while doing so)
for elem do
    set -- "$@" --exclude="$directory/$elem"
    shift
done

# Run tar
tar -cz -f tmp.tar.gz "$@" "$directory"

引用注$@shコードとの両方${exclude[@]}${exclude_opts[@]}bashコード。これにより、リストが個別に引用された要素に展開されます。

関連:


2
mix(){
        p=$1; shift; q=$1; shift; c=
        i=1; for a; do c="$c $q \"\${$i}\""; i=$((i+1)); done
        eval "${p%\%*}$c${p#*\%}"
}
mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
mix 'tar % -zcf tmp.tar.gz' --exclude "${EXCLUDE[@]}"

ここで答えを拡張します。これはバシズムに依存せず、debianやでも正常に動作/bin/shbusyboxます。


あなたの助けをありがとうございました、しかし私はevalが本当に好きではありません、それは非常に危険です...さらに、このコードは理解するのが非常に難しいです、あなたにはもっと簡単なものはありませんか?:/スクリプトは配布されるので、できるだけシンプルにする必要があります...
ShellCode

危険ではありません。で実行しset -xます。正確に何を理解していないのですか?
モスビー2018年

また、stackoverflowで元の回答を読んでください。デモが含まれています。
モスビー2018年

それはかなりうまくいきますが...誰かがより明確な答えを持っているかどうかを確認するために待っています、そうでなければ私はあなたを受け入れます。そのコードに問題はないかもしれませんが、evalが表示されるたびに、コードがコマンドインジェクションにつながる可能性があるため、それを回避しようとしています
ShellCode

私は答えをインデックス> 9の修正で更新しました
。evalを
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.