37

I have an executable that is used in a way such as the following:

executable -v -i inputFile.txt -o outputFile.eps

In order to be more efficient, I want to use a Bash variable in place of the input file. So, I want to do something like the following:

executable -v -i ["${inputData}"] -o outputFile.eps

Here, the square brackets represent some clever code.

Do you know of some trick that would allow me to pipe information into the described executable in this way?

Many thanks for your assistance

d3pd
  • 7,935
  • 24
  • 76
  • 127
  • It's a bit unclear just what you want to happen. Like, what is value of inputData? – hyde Feb 12 '13 at 19:55
  • 1
    "${inputData}" is simple, ASCII data which I want to 'package' as a file without actually using a file (which may need to be stored in non volatile memory). The user mikyra suggests an approach involving process substitution which I think is exactly I need. Thanks for your help. – d3pd Feb 13 '13 at 21:13
  • Ah, now I got it... Cool, I didn't know of that. Apparently it is a *bash* feature, not supported by plain *sh* or *dash*, so better remember to use `#!/bin/bash` when using that in a script. +1+1 – hyde Feb 13 '13 at 21:21

4 Answers4

63

You can use the following construct:

<(command)

So, to have bash create a FIFO with the command as the output for you, instead of your attempted -i ["${inputData}"], you would do:

-i <(echo "$inputData")

Therefore, here is your final total command:

executable -v -i <(echo "$inputData") -o outputFile.eps
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
mikyra
  • 10,077
  • 1
  • 40
  • 41
  • 2
    This process substitution is exactly what I need. Thank you very much for your assistance! – d3pd Feb 13 '13 at 21:10
  • 1
    I encountered some command that need to seek the input file, where fifo pipe doesn't work. Zsh has a =() implemented as a temp file, which works well. – misssprite Jan 29 '15 at 07:40
  • 4
    https://www.gnu.org/software/bash/manual/bash.html#Process-Substitution worth to read this section – Sławosz Nov 30 '15 at 08:51
  • 2
    This fails if `inputData` contains literal backslashes, or is `-e` – Eric Mar 27 '18 at 17:53
  • For a solution that works in the cases that @Eric mentions, see [here](https://stackoverflow.com/a/51022016/5353461). – Tom Hale Jun 25 '18 at 11:08
19

Echo is not safe to use for arbitrary input.

To correctly handle pathological cases like inputdata='\ntest' or inputdata='-e', you need

executable -v -i <(cat <<< "$inputData")

In zsh, the cat is not necessary


Edit: even this adds a trailing newline. To output the exact variable contents byte-by-byte, you need

executable -v -i <(printf "%s" "$inputData")
Eric
  • 95,302
  • 53
  • 242
  • 374
3

Note: zsh only:

To get a filename containing the contents of ${variable}, use:

<(<<<${variable})

Note:

  • <<<${variable} redirects STDIN to come from ${variable}
  • <<<${variable} is equivalent to (but faster than) cat <<<${variable}

So for the OP's case:

executable -v -i <(<<<${inputData}) -o outputFile.eps
Tom Hale
  • 40,825
  • 36
  • 187
  • 242
  • 2
    This also emits a trailing newline after the contents of `variable`, which in most cases doesn't matter, but might be worth drawing attention to – Eric Jun 28 '18 at 17:22
1

I couldn't find a better solution than making temporary file and reference it into a variable. For example:

key=$(mktemp);    # Creating a random file in the tmp folder
echo "some data" > $key;    # Filling the file with content
ssh -i $key user@localhost

I assume when the bash session is close, the variable and temporary file is cleared

Raz Kheli
  • 41
  • 4
  • Actually, `mktemp` is an external utility, so it's up to your program to clean up the file when it's done with it – JM0 Jul 10 '23 at 19:09