1

Any one know why this works?

cat `echo "FilenameWithoutSpaces.txt"` # shows file content

stdout:

SHOW FILE CONTENT

And this not?

cat `echo "Filename\ With\ Spaces.txt"` # trying to show "Filename With Spaces.txt" content

stdout:

cat: 'Filename': No such file or directory

cat: 'With': No such file or directory

cat: Spaces.txt: No such file or director

What would be the correct way to pass an output (with spaces) as a input of another command?

The example above is a simplified case of what i need. What I have to to is:

To use list of files (that may contain spaces) returned by a command as argument for another command.

  • 1
    Why are you executing echo? Why not just cat "Filename With Spaces.txt"? – Red Cricket Jan 07 '21 at 00:32
  • 1
    See ["Why does shell ignore quoting characters in arguments passed to it through variables?"](https://stackoverflow.com/questions/12136948/why-does-shell-ignore-quoting-characters-in-arguments-passed-to-it-through-varia) – Gordon Davisson Jan 07 '21 at 00:33
  • @GordonDavisson, the aproaches suggested by your link seems to be suitable to my specific problem, thanks by you suggestion. – Elvis Rock Code Jan 07 '21 at 11:23

2 Answers2

1

For this particular case:

cat "$(echo "Filename\ With\ Spaces.txt")"

Since the case is a bit contrived, I can't really say what the correct thing is for your actual situation. What is meant by a "list of files"? Is that a list of files that are separated by newlines? How will you handle files that contain a newline in the name? Is it a list of null separated files, or is the list comma separated? In general, my opinion would be that the correct solution is to ban the use of whitespace in filenames. If that's not an option, the general principle would be to always put quotes around any string that may contain elements of IFS.

However. (Note this "however" should be read as "the following is a terrible hack that should never be done because the correct approach is to ban the use of whitespace in filenames"). Assuming that by a "list of files" you mean that each name is distinguished from the next by the presence of a newline in the string, you might try something like:

printf '1st name\n2nd name\n' | { a=(); while read arg; do a+=("$arg"); done; 
    cmd "${a[@]}"
}

The above will invoke cmd with each line as a single argument. It would be much more reasonable to require that the list of inputs be zero separated, which would allow you to use xargs with something like:

printf '1st name\0002nd name\000' | xargs -0 cmd

Until you properly define what you mean by "list of files", no robust solution is possible.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • As the previous solution, your aproach works for just one file if i remove the back slashes as follows: `"$(echo "Filename With Spaces.txt")"` However i need it to work with a several files something like: `"$(echo "Filename With Spaces.txt Filename2 With Spaces.txt")"` with echo output splited in two or more arguments for cat command. do you know how to proceed? – Elvis Rock Code Jan 07 '21 at 09:38
  • This is not a coding problem but a theoretical problem. Given the string "This is a string", how do you know if that is two files named "This is a", and "string", or 4 files, or 3 files named "This", "is a", and "string"? You need some form of delimiter. If you want to use the suffix ".txt" as a marker, you'll need to write some logic for it. The shell doesn't work with lists; everything is a string. – William Pursell Jan 07 '21 at 13:47
  • Anyway, if i execute, in command line, something like this: `cat file1\ xxx.txt file2\ yyy.txt` the command line understands that i am passing two files and correct outputs both contents, that's why i was i was looking for a way to use the same principle. unfortunately i do not have control if a user decides to use whitespaces to name files or not, since the file system allows it, so i have to deal with it. – Elvis Rock Code Jan 07 '21 at 17:31
  • When you type `cat file1\ xxx.txt file2\ yyy.txt` the shell calls `cat` with 2 arguments. But you have a theoretical problem. If the user gives you the string `foo bar`, how do you know if that is one file with a space in the name or two files? – William Pursell Jan 07 '21 at 17:35
  • I just gave up, I decided to remove all space from filenames and re-write my script, to remove spaces i did as follows: https://stackoverflow.com/questions/2709458/how-to-replace-spaces-in-file-names-using-a-bash-script – Elvis Rock Code Jan 07 '21 at 20:57
0

This is due to the way strings are handled and passed are argument in bash. When you run echo "Filename\ With\ Spaces.txt" the output is Filename With Spaces.txt which is exaclty what you are expecting. So the full command is essentially the same as cat Filename With Spaces.txt and cat is trying to find 3 files with the names Filename, With, and Spaces.txt.

When bash looks for those is it not likely to find them and spits out those error messages you are seeing. When there are no spaces, the filename is read as a single parameter and so you do not encounter the same issue.

To force the command to work with and without spaces you need to add qutoations around the command substituion:

cat "`echo "Filename\ With\ Spaces.txt"`"

This command will expand the out put of the echo and keep it as a single argument.

joshmeranda
  • 3,001
  • 2
  • 10
  • 24
  • I have tested you solution and in my console, when I execute: $ echo "Filename\ With\ Spaces.txt" it returns Filename\ With\ Spaces.txt (with back slashes) not Filename With Spaces.txt (no slashes).So, to make your command to work i have to execute as follows: $ cat "`echo "Filename With Spaces.txt"`" Besides that i have to make it work with more than one file as argument like: cat "`echo "Filename1\ With\ Spaces.txt Filename2\ With\ Spaces.txt"`" Do you know how to do? – Elvis Rock Code Jan 07 '21 at 09:24