Literal and syntactic quotes are two different things: The former tell the shell how to parse the code you enter, the latter are part of your data.
When you run:
echo '"filenames.dat"' >filenames.dat
line=$(head -n 1 "filenames.dat")
...the double quotes inside the line returned by head
are literal: They're part of the data.
By contrast, in [ -e "$line" ]
, the quotes there in the code are syntactic; they tell the shell to treat the results of the variable expansion as completely literal, without string-splitting or glob expansion. (This is correct and desirable).
When [ -e "$line" ]
is run, then, what we check for existence is the literal contents of the variable named line
. Because those literal contents include literal quotes returned by head
, we the look for file and directory names that contain literal quotes.
Because your actual filenames don't contain literal quotes, the result is that the files are not found.
If you want to keep your data format as it is, with literal quotes in the data, follow the guidance in Bash: Reading quoted/escaped arguments correctly from a string