次のようにtarを使用して単純なバックアップスクリプトを設定しようとしています。
#!/bin/bash
TIME=`date +%F_%H-%M`
FILENAME=backup-$TIME.tar.gz
SRCDIR="~/PI/tutos/* ~/scripts/*"
DESTDIR=/media/sf_ubuntuSharedFolder/backups
tar cvpzf $FILENAME $SRCDIR
ただし、$ SRCDIRを使用すると、直接拡張すると発生しないtarエラーが発生します。
alex@ALeX-VirtualBox:~$ save
tar: ~/PI/tutos/*: Cannot stat: No such file or directory
tar: ~/scripts/*: Cannot stat: No such file or directory
シェル変数の使用にはどのような問題がありますか?それ以外の場合は、フォルダリストを1行でtarに渡すことができますか?
答え1
問題は、~
-expansionが変数が拡張された場合(引用$SRCDIR
符なしの変数を引用する場合)ではなく、二重引用符内で(変数を割り当てる場合)実行されないことですSRCDIR
。
引用符がない場合は、$SRCDIR
分割+グローブ演算子を呼び出します。つまり、スカラー$SRCDIR
変数()に格納されている~/PI/tutos/* ~/scripts/*
文字列を最初に$IFS
分割(デフォルトは空白)してから、各単語をワイルドカード、つまりファイルリストと一致するように拡張パターンとして処理します。
~
ホームディレクトリに展開されないため、他の文字と同じように扱われるので、現在のディレクトリのディレクトリになるディレクトリ内のファイルを探します。あなたの場合、ディレクトリは存在しません~
。~/PI/tutos
~
$SRCDIR
最善の方法は、配列を作成し、割り当て時にglobを拡張することです。
SRCDIR=(~/PI/tutos/* ~/scripts/*) # ~ and globs expanded at this point
tar cvpzf "$FILENAME" "${SRCDIR[@]}"
Split + glob演算子を適用することは$FILENAME
意味がないため、引用符を使用して無効にします$FILENAME
。
矛盾がある場合は~/PI/tutos/*
そのまま残り、エラーが発生し続けますtar
。これを防ぐには、次のようにします。
shopt -s nullglob # remove non-matching globs
SRCDIR=(~/PI/tutos/* ~/scripts/*)
if ((${#SRCDIR[@]} != 0)); then
tar cvpzf "$FILENAME" "${SRCDIR[@]}"
fi
次のことをしたい場合があります。
SRCDIR="$HOME/PI/tutos/* $HOME/scripts/*"
tar cvpzf "$FILENAME" $SRCDIR
変数(例えば$HOME
)は二重引用符で拡張されるため、$HOME
グローバル文字または$IFS
。
~
引用符がなく、最初または後ろにある場合、sは変数の割り当てで拡張されます:
(したがって$PATH
、...などの$LD_LIBRARY_PATH
変数の割り当てで機能しますPATH=~/bin:~/sbin
)。したがって、次のことをしたい場合があります。
SRCDIR=~/PI/tutos/*:~/scripts/* # ~ (not globs) expanded here
IFS=:
tar cvpzf "$FILENAME" $SRCDIR
ただし、上記と同様に、文字(今回はホームディレクトリをコロンで区切られたテーブルとして定義するため、可能性が低い)やグローバル文字が$HOME
含まれていると機能しません。$IFS
:
/etc/passwd