问题
My bash script receives a filename (or relative path) as a string, but must then read from that file. I can only read from a filename if I declare it as a literal directly in the script (without quotes)...which is impossible for arguments since they are implicitly strings to begin with. Observe:
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
As stated above, I can't pass a command line argument to the routines above since I get the same behavior that I get on the quoted strings.
回答1:
This is part of the rules of ~
-expansion. It is clearly stated in the Bash manual that this expansion is not performed when the ~
is quoted.
Workaround 1
Don't quote the ~
.
file=~/path/to/file
If you need to quote the rest of the filename:
file=~/"path with spaces/to/file"
(This is perfectly legal in a garden-variety shell.)
Workaround 2
Use $HOME
instead of ~
.
file="$HOME/path/to/file"
BTW: Shell variable types
You seem to be a little confused about the types of shell variables.
Everything is a string.
Repeat until it sinks in: Everything is a string. (Except integers, but they're mostly hacks on top of strings AFAIK. And arrays, but they're arrays of strings.)
This is a shell string: "foo"
. So is "42"
. So is 42
. So is foo
. If you don't need to quote things, it's reasonable not to; who wants to type "ls" "-la" "some/dir"
?
来源:https://stackoverflow.com/questions/16703624/bash-interpret-string-variable-as-file-name-path