2016-08-01 11 views
2

私はこのようなバックアップ用のスクリプトを書いています:私はそれがすべてのファイルまたは唯一のデルタをタールように、tarコマンドに単一の変数$delta_cmdを渡したい可変数のパラメータをシェルコマンドに渡すには?

dir="$1" 
mode="$2" 
delta="$3" 

for file in "$dir/backup."*".$mode.tar.gz"; do 
    [ "$file" -nt "$ref" ] && ref="$file" 
done 

if [ "$delta" = "true" ]; then 
    delta_cmd=-N "'$ref'" 
fi 

backup_file="$dir/backup.$(date +%Y%m%d-%H%M%S).$mode.tar.gz" 

case "$mode" in 
    config) 
     tar -cpzvf "$backup_file" $delta_cmd \ 
      /etc \ 
      /usr/local 
      ;; 
    # still other modes here... 
esac 

backup.sh最後のバックアップ以降のファイルは、$deltaの値によって異なります。

上記のコードは、エラーメッセージを作成し、$deltaがtrueに設定されている場合、デルタファイルを正しくタールしません。それを修正するには?

P.S:スクリプトはPOSIX互換の方がよいでしょう。あなたは、部分的/完全なコマンドラインを格納するためBASHアレイを使用する必要があります

+1

それはです* POSIX互換にすることは可能ですが、セキュリティ上の脆弱性( 'eval'を使う)や' $ @ '(' delta_cmd'文字列の使用とはかなり互換性がありません)カプセル化することを意味するその配列のスクリプトグローバル値をオーバーライドしたくない場合は、関数内でコード化します。文字列変数(配列とは対照的に)が引数リストやコマンドを格納するために安全に使用できない理由については、BashFAQ#50を参照してください。http://mywiki.wooledge.org/BashFAQ/050 –

+0

'$ @'を上書きする方法についてもっと詳しく? –

+1

回答を追加しました。ところで、このコードには、適切なMCVE(**最小**、完全で検証可能な例; http://stackoverflow.com/help/mcveを参照)を作成するために削減できる余裕があります。私の答えに内容を含めることを非常に躊躇しています。これには 'ls 'の構文解析などの悪い習慣が含まれていますが、そのコードのより良い慣行の置き換えもやっています。 –

答えて

1

set --     # clear [email protected] 
if [ -f "$ref" ]; then 
    set -- "[email protected]" -N "$ref" # add -N "$ref" to [email protected] 
fi 

tar ... "[email protected]" ...  # expand [email protected] into command line 

をすべてのコンテキストでこれを入れて、上書きに対してメインの引数リストを保護するためには、次のようになります。

#!/bin/sh 

main() { 
    # if current shell supports "local", prevent variables from leaking 
    # ...some "POSIX" shells, such as ash, will be fine with this. 
    local dir mode delta target_file backup_file 2>&1 ||: 

    dir=$1 
    mode=$2 
    delta=$3 

    set -- # clear [email protected] 

    for file in "$dir/backup."*".$mode.tar.gz"; do 
     [ "$file" -nt "$ref" ] && ref="$file" 
    done 

    if [ "$delta" = "true" ]; then 
     set -- "[email protected]" -N "$ref" 
    fi 

    target_file="$dir/backup.$(date +%Y%m%d-%H%M%S).$mode.tar.gz" 

    case "$mode" in 
     config) 
      tar -cpzvf "$target_file" "[email protected]" \ 
       /etc \ 
       /usr/local 
      ;; 
     # still other modes here... 
    esac 
} 

main "[email protected]" 
+0

ありがとうございます。これは参考になります。コードフラグメントを 'backup()(...)'のようなサブシェルの関数に置くと、$ @それを上書きしませんか? –

+1

が正しい場合、その関数の '$ @ 'を上書きするだけです。関数は異なるスタックフレームにあり、独自の引数リストもあるので、 'backup()(...)'、 'backup(){...}'は実際には必要ありません。 –

+0

ありがとうございます。それはうまくいく。 –

1

#!/bin/bash 

DIR=/home/sysop/backup 
mode=main 
delta=false 

REF=$(ls -t "$DIR"/system.*.$mode.tar.gz "$DIR"/system.*.$mode-delta.tar.gz 2>/dev/null | head -n 1) 
REF=$(readlink -f "$REF") 

if [ "$delta" = true ]; then 
    delta_cmd=(-N "$REF") 
    delta_suffix=("-delta") 
fi 

target_file="$DIR/system.$(date +%Y%m%d-%H%M%S).$mode$delta_suffix.tar.gz" 

tar -cpzvf "$target_file" "${delta_cmd[@]}" \ 
    /etc \ 
    /usr/local \ 
    /var/log \ 
    /var/spool \ 
    /home/*/logs 

私はまた、あなたのスクリプト内lsコマンドの出力の解析を避けることを示唆しています。 POSIX準拠のアプローチとして、検討し

+0

構文エラーのためにPOSIX-lyでは動作しないようです。私もbashを使ってみましたが、$ delta = trueの場合、結果は以前のようにエラーになります。 –

+0

このスクリプトはBASHで実行する必要があります。 BASHの使用中に正確なエラーが何であるか教えていただけますか? – anubhava

+0

私の実際のスクリプトは、$ DIRに別のパスを使用しています。 tar:不明な日付形式 '/ path/to/subdir'の代わりに-9223372036854775807を代入してください。 tar:after-space/system.20160802-004650.main-delta.tar.gz ':Can not stat:いいえそのようなファイルやディレクトリ –

関連する問題