0

As show below, command-substitution changes the interpretation of quoted command-line arguments. What is going on under the hood, and is there a workaround?

$ cat dumpargs.sh
#! /usr/bin/env bash
for i in "$@"
   {
   echo "$i"
   }

$ cat testfile.txt 
'1 space' '2  space'

$ ./dumpargs.sh $(cat testfile.txt) ## produced undesired output
'1
space'
'2
space'

$ ./dumpargs.sh '1 space' '2  space' ## produces desired output
1 space
2  space
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
  • http://shellcheck.net/ would have caught your problem (lack of quoting leading to string-splitting) for you. Though the expectation that *literal* quotes (which don't impact string-splitting) would be treated as *syntactic* ones (which do) is perhaps a larger issue. – Charles Duffy Mar 10 '17 at 21:46
  • This is also very closely related to [BashFAQ #50](http://mywiki.wooledge.org/BashFAQ/050). – Charles Duffy Mar 10 '17 at 21:46
  • 2
    Short answer, use `xargs`: `cat testfile.txt |xargs ./dumpargs.sh` – Brent Bradburn Mar 10 '17 at 23:01
  • 1
    I'd suggest skipping the `cat` -- it's more efficient to read straight from a file than from a FIFO that's being written to by a separate program that's reading from the file. Thus, ` – Charles Duffy Mar 10 '17 at 23:03

1 Answers1

2

When you write ./dumpargs.sh '1 space' '2 space' on the command line, the shell interprets the single-quotes before passing arguments to the script. Argument #1 will have the value 1 space, argument #2 will ahve the value 2 space. The single-quotes are not part of the values.

When you write ./dumpargs.sh $(cat testfile.txt), the shell will not try to interpret the content of testfile.txt. The shell only interprets the actual text entered on the command line. Substituted content like this example, or for example values of variables are not interpreted, but used literally. Finally, the shell performs word splitting on the string on the command line, using the delimiters in IFS. So the single-quotes will be used literally, and the content is simply split by whitespace.

One possible workaround is to store one argument per line, without single-quotes, and make dumpargs.sh take the arguments from standard output:

while read -r line; do
    echo "$line"
done

You can call it with ./dumpargs.sh < testfile.txt.

janos
  • 120,954
  • 29
  • 226
  • 236
  • Your workaround isn't what I was looking for, but I appreciate the comments about the differences in how things are interpreted under the different usages. Everything related to Bash string handling makes me scratch my head, and this brings a bit of clarity. – Brent Bradburn Mar 10 '17 at 22:56