Bash: интерпретировать строковую переменную как имя файла/путь

My bash script получает имя файла (или относительный путь) в виде строки, но затем должен читать из этого файла. Я могу читать только из имени файла, если объявить его как литерал непосредственно в script (без кавычек)... что невозможно для аргументов, так как они неявно начинаются с начала. Обратите внимание:

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

ДОХОДНОСТЬ:

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

Как указано выше, я не могу передать аргумент командной строки в описанные выше процедуры, так как я получаю то же поведение, что и в цитированных строках.

Ответы

Ответ 1

Это часть правил ~ -расширения. В руководстве Bash четко указано, что это расширение не выполняется при цитировании ~.

Обходной путь 1

Не цитируйте ~.

file=~/path/to/file

Если вам нужно процитировать остальную часть имени файла:

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

(Это совершенно законно в садовой разновидности.)

Обходной путь 2

Используйте $HOME вместо ~.

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

BTW: типы переменных оболочки

Вы, кажется, немного смущены о типах переменных оболочки.

Все это строка.

Повторяйте до тех пор, пока он не опустится: Все это строка. (кроме целых чисел, но в основном это хаки поверх строк AFAIK и массивы, но это массивы строк.)

Это строка оболочки: "foo". Так что "42". Итак, 42. Так что foo. Если вам не нужно цитировать вещи, разумно не делать этого; кто хочет набрать "ls" "-la" "some/dir"?