web-dev-qa-db-ja.com

bash:文字列変数をファイル名/パスとして解釈します

Bashスクリプトはファイル名(または相対パス)を文字列として受け取りますが、そのファイルから読み取る必要があります。スクリプト内で直接リテラルとして宣言する場合(引用符なし)にのみファイル名から読み取ることができます...これは暗黙的に文字列であるため、引数には不可能です。観察する:

a="~/test.txt"
#Look for it
if [[ -a $a ]] ; then
    echo "A Found it"
else
    echo "A Error"
fi
#Try to use it
while read line; do
    echo $line
done < $a

b='~/test.txt'
#Look for it
if [[ -a $b ]] ; then
    echo "B Found it"
else
    echo "B Error"
fi
#Try to use it
while read line; do
    echo $line
done < $b

c=~/test.txt
#Look for it
if [[ -a $c ]] ; then
    echo "C Found it"
else
    echo "C Error"
fi
#Try to use it
while read line; do
    echo $line
done < $c

YIELDS:

A Error
./test.sh: line 10: ~/test.txt: No such file or directory
B Error
./test: line 12: ~/test.txt: No such file or directory
C Found it
Hello

上記のように、上記のルーチンにコマンドライン引数を渡すことはできません。引用符で囲まれた文字列と同じ動作をするからです。

17
Keith Wiley

これは、~- expansionのルールの一部です。 ~が引用されている場合、この拡張は実行されないことがBashマニュアルに明確に記載されています。

回避策1

~を引用しないでください。

file=~/path/to/file

ファイル名の残りを引用する必要がある場合:

file=~/"path with spaces/to/file"

(これは、園芸品種のシェルでは完全に合法です。)

回避策2

$HOMEの代わりに~を使用します。

file="$HOME/path/to/file"

ところで:シェル変数タイプ

シェル変数のタイプについて少し混乱しているようです。

すべてが文字列です。

沈み込むまで繰り返します:すべてが文字列です。(整数を除きますが、ほとんどの場合、文字列の上でのハックです。配列。ただし、文字列の配列。)

これは"foo"というシェル文字列です。 "42"も同様です。 42も同様です。 fooも同様です。物事を引用する必要がない場合は、そうしないのが合理的です。誰が"ls" "-la" "some/dir"と入力したいですか?

33
michaelb958