変数を ~/directory に設定しても拡張されません。

変数を ~/directory に設定しても拡張されません。

次のように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

関連情報