0

I want to read in from a file "filenames.dat" that contains the path + filenames of other files

$ more filenames.dat
"/home/test1.dat"
"/home/test2.dat"
"/home/test3.dat"

and then check if those files exist. This is the code for the first line in filenames.dat

line=$(head -n 1 "filenames.dat")
[ -e "$line" ] && echo "files do exist" || echo "files do not exist"

However I get "files do not exist" even if they do. If instead I do

[ -e "/home/test1.dat" ] && echo "files do exist" || echo "files do not exist"

than the file exists!

user3036416
  • 1,205
  • 2
  • 15
  • 28
  • Quotes? What's the syntax of this file? JSON strings? Shell-quoted strings? Something else? – Charles Duffy Oct 04 '17 at 15:34
  • 1
    To be clear, your code is looking for a file named `"/home/test1.dat"`, not `/home/test1.dat`. – Charles Duffy Oct 04 '17 at 15:35
  • @CharlesDuffy so do I have to remove the quotes in filenames.dat? – user3036416 Oct 04 '17 at 15:36
  • 1
    See https://stackoverflow.com/questions/26067249/bash-reading-quoted-escaped-arguments-correctly-from-a-string for a detailed discussion. – Charles Duffy Oct 04 '17 at 15:37
  • 1
    That said, removing those literal quotes is indeed one way to fix this problem. If you want to *really* do things correctly, though, you're better off not using newline-delimited files to list names at all. (Keep in mind that filenames in UNIX are allowed to contain newline literals; if you have a file created with `touch $'foo\nbar'`, you can't put it in a newline-delimited filenames at all). – Charles Duffy Oct 04 '17 at 15:39

1 Answers1

2

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

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441