How to pass a string to a command that expects a file?












21















Suppose a program cook takes one argument: the pathname of a text file containing the recipe of the food to cook. Suppose I wish to call this program from within a bash script, also suppose I already have the recipe in a string variable:



#!/bin/bash

the_recipe="$(cat << EOF
wash cucumbers
wash knife
slice cucumbers
EOF
)"

cook ... # What should I do here? It expects a file, but I only have a string.


How can I pass the recipe to the command when it expects a filename argument?



I thought about creating a temporary file just for the purpose passing a file, but I wish to know if there are alternative ways to solve this problem.










share|improve this question





























    21















    Suppose a program cook takes one argument: the pathname of a text file containing the recipe of the food to cook. Suppose I wish to call this program from within a bash script, also suppose I already have the recipe in a string variable:



    #!/bin/bash

    the_recipe="$(cat << EOF
    wash cucumbers
    wash knife
    slice cucumbers
    EOF
    )"

    cook ... # What should I do here? It expects a file, but I only have a string.


    How can I pass the recipe to the command when it expects a filename argument?



    I thought about creating a temporary file just for the purpose passing a file, but I wish to know if there are alternative ways to solve this problem.










    share|improve this question



























      21












      21








      21


      1






      Suppose a program cook takes one argument: the pathname of a text file containing the recipe of the food to cook. Suppose I wish to call this program from within a bash script, also suppose I already have the recipe in a string variable:



      #!/bin/bash

      the_recipe="$(cat << EOF
      wash cucumbers
      wash knife
      slice cucumbers
      EOF
      )"

      cook ... # What should I do here? It expects a file, but I only have a string.


      How can I pass the recipe to the command when it expects a filename argument?



      I thought about creating a temporary file just for the purpose passing a file, but I wish to know if there are alternative ways to solve this problem.










      share|improve this question
















      Suppose a program cook takes one argument: the pathname of a text file containing the recipe of the food to cook. Suppose I wish to call this program from within a bash script, also suppose I already have the recipe in a string variable:



      #!/bin/bash

      the_recipe="$(cat << EOF
      wash cucumbers
      wash knife
      slice cucumbers
      EOF
      )"

      cook ... # What should I do here? It expects a file, but I only have a string.


      How can I pass the recipe to the command when it expects a filename argument?



      I thought about creating a temporary file just for the purpose passing a file, but I wish to know if there are alternative ways to solve this problem.







      bash shell-script






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 11 hours ago









      Kusalananda

      135k17255421




      135k17255421










      asked 12 hours ago









      FluxFlux

      345113




      345113






















          3 Answers
          3






          active

          oldest

          votes


















          27














          You can use the "fake" filename /dev/stdin which represents the standard input.



          So execute this:



          echo "$the_recipe" | cook /dev/stdin


          The echo command and the pipe sends the contents of the specified variable to the standard input of the next command cook, and that opens the standard input (as a separate file descriptor) and reads that.






          share|improve this answer
























          • This is a very smart solution!

            – Panki
            12 hours ago






          • 2





            Is this method limited to commands that take only one argument? If cook takes two file arguments, and I have the_recipe1 and the_recipe2 (both of which are string variables), will this method still work?

            – Flux
            11 hours ago








          • 5





            @Flux You can do it with /dev/fd but that's beyond the scope of your initial question. But I think you'll find examples of that in unix.stackexchange.com/questions/tagged/file-descriptors

            – Gilles
            11 hours ago











          • This is not 100% portable, though it does come pretty close in practice: unix.stackexchange.com/q/36403/91565

            – Kevin
            38 mins ago



















          24














          One other way to use the process-substitution feature of the bash shell causes a FIFO to be created under /tmp or /var/tmp, or uses a named file descriptor (/dev/fd/*), depending on the operating system. The substitution syntax (<(cmd)) is replaced by the name of the FIFO or FD, and the command inside it is run in the background.



          cook <(printf '%sn' "${the_recipe}")


          The command cook now reads the content of the variable as if it were available in a file.



          This could also be used for more than one input file:



          cook <(printf '%sn' "${the_1st_recipe}") <(printf '%sn' "${the_2nd_recipe}")





          share|improve this answer





















          • 4





            Alternatively, cat <<<"$the_recipe" inside the process substitution.

            – Kusalananda
            11 hours ago






          • 5





            Note that process substitution is a ksh feature (now also supported by zsh and bash). Chances are cook will expect a text file, so you should probably make it '%sn' instead of '%s'. See also <(<<<$the_recipe) in zsh.

            – Stéphane Chazelas
            11 hours ago



















          14














          It depends on the application's capabilities. It may or may not insist on a named file, and it may or may not insist on a seekable file.



          Anonymous pipe



          Some applications just read input from anywhere. Typically they default to reading from standard input. If you have the data in a string and you want to pass it to the application's standard input, there are a few ways. You can pass the information via a pipe:



          printf '%s' "$the_recipe" | cook     # passes $the_recipe exactly
          printf '%sn' "$the_recipe" | cook # passes $the_recipe plus a final newline


          Don't use echo here because depending on the shell, it might mangle backslashes.



          If the application insists on a file argument, it might accept - to mean standard input. This is a common convention, but not systematic.



          printf '%sn' "$the_recipe" | cook -


          If the application needs an actual file name, pass /dev/stdin to mean standard input.



          printf '%sn' "$the_recipe" | cook /dev/stdin


          For some applications, even this is not enough: they need a file name with certain properties, for example with a given extension, or they need a file name in a writable directory where they create temporary files. In such cases, you generally need a temporary file, although sometimes a named pipe is enough.



          Named pipe



          It's possible to give a pipe a name. I mention this for completeness, but it's rarely the most convenient way. It does avoid getting the data on disk. It's suitable if the application needs a file with constraints on the name, but doesn't need the file to be seekable.



          mkfifo named.pipe
          printf '%sn' "$the_recipe" >named.pipe & writer=$!
          cook named.pipe
          rm named.pipe
          wait "$writer"


          (Error checking omitted.)



          Temporary file



          If the application needs a seekable file, you need to create a temporary file. A seekable file is one where the application can go back and forth, reading arbitrary portions at a time. A pipe doesn't allow this: it needs to be read from start to finish, in sequence, without ever going backwards.



          Bash, ksh and zsh have a convenient syntax to pass a string as input via a temporary file. Note that they always append a newline to the string (even if there's already one).



          cook <<<"$the_recipe"


          With other shells, or if you want to control which directory contains the temporary file, you need to create the temporary file manually. Most unices provide a mktemp utility to create the temporary file securely. (Never use something like … >/tmp/temp.$$! It allows other programs, even running as other users, to hijack the file.) Here's a script that creates a temporary file and takes care of removing it if interrupted.



          tmp=
          trap 'rm -f "$tmp"' EXIT
          trap 'rm -f "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -f "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -f "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp)
          printf '%sn' "$the_recipe" >"$tmp"
          cook "$tmp"


          To choose where to create the temporary file, set the TMPDIR environment variable for the mktemp call. For example, to create the temporary file in the current directory rather than the default location for temporary files:



          tmp=$(TMPDIR="$PWD" mktemp)


          (Using $PWD rather than . gives you an absolute file name, which means you can safely call cd in your script without worrying that $tmp will no longer designate the same file.)



          If the application needs a file name with a certain extension, you need to create a temporary directory and create a file there. To create the temporary directory, use mktemp -d. Again, set the TMPDIR environment variable if you want to control where the temporary directory is created.



          tmp=
          trap 'rm -rf "$tmp"' EXIT
          trap 'rm -rf "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -rf "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -rf "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp -d)
          printf '%sn' "$the_recipe" >"$tmp/myfile.ext"
          cook "$tmp/myfile.ext"





          share|improve this answer
























          • I'm pretty sure you can use a here-doc as input, too (I think you might have to use <(cat <<END) or similar; it's years since I've done that).

            – Toby Speight
            8 hours ago











          Your Answer








          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "106"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f505828%2fhow-to-pass-a-string-to-a-command-that-expects-a-file%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          3 Answers
          3






          active

          oldest

          votes








          3 Answers
          3






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          27














          You can use the "fake" filename /dev/stdin which represents the standard input.



          So execute this:



          echo "$the_recipe" | cook /dev/stdin


          The echo command and the pipe sends the contents of the specified variable to the standard input of the next command cook, and that opens the standard input (as a separate file descriptor) and reads that.






          share|improve this answer
























          • This is a very smart solution!

            – Panki
            12 hours ago






          • 2





            Is this method limited to commands that take only one argument? If cook takes two file arguments, and I have the_recipe1 and the_recipe2 (both of which are string variables), will this method still work?

            – Flux
            11 hours ago








          • 5





            @Flux You can do it with /dev/fd but that's beyond the scope of your initial question. But I think you'll find examples of that in unix.stackexchange.com/questions/tagged/file-descriptors

            – Gilles
            11 hours ago











          • This is not 100% portable, though it does come pretty close in practice: unix.stackexchange.com/q/36403/91565

            – Kevin
            38 mins ago
















          27














          You can use the "fake" filename /dev/stdin which represents the standard input.



          So execute this:



          echo "$the_recipe" | cook /dev/stdin


          The echo command and the pipe sends the contents of the specified variable to the standard input of the next command cook, and that opens the standard input (as a separate file descriptor) and reads that.






          share|improve this answer
























          • This is a very smart solution!

            – Panki
            12 hours ago






          • 2





            Is this method limited to commands that take only one argument? If cook takes two file arguments, and I have the_recipe1 and the_recipe2 (both of which are string variables), will this method still work?

            – Flux
            11 hours ago








          • 5





            @Flux You can do it with /dev/fd but that's beyond the scope of your initial question. But I think you'll find examples of that in unix.stackexchange.com/questions/tagged/file-descriptors

            – Gilles
            11 hours ago











          • This is not 100% portable, though it does come pretty close in practice: unix.stackexchange.com/q/36403/91565

            – Kevin
            38 mins ago














          27












          27








          27







          You can use the "fake" filename /dev/stdin which represents the standard input.



          So execute this:



          echo "$the_recipe" | cook /dev/stdin


          The echo command and the pipe sends the contents of the specified variable to the standard input of the next command cook, and that opens the standard input (as a separate file descriptor) and reads that.






          share|improve this answer













          You can use the "fake" filename /dev/stdin which represents the standard input.



          So execute this:



          echo "$the_recipe" | cook /dev/stdin


          The echo command and the pipe sends the contents of the specified variable to the standard input of the next command cook, and that opens the standard input (as a separate file descriptor) and reads that.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 12 hours ago









          wurtelwurtel

          10.8k11627




          10.8k11627













          • This is a very smart solution!

            – Panki
            12 hours ago






          • 2





            Is this method limited to commands that take only one argument? If cook takes two file arguments, and I have the_recipe1 and the_recipe2 (both of which are string variables), will this method still work?

            – Flux
            11 hours ago








          • 5





            @Flux You can do it with /dev/fd but that's beyond the scope of your initial question. But I think you'll find examples of that in unix.stackexchange.com/questions/tagged/file-descriptors

            – Gilles
            11 hours ago











          • This is not 100% portable, though it does come pretty close in practice: unix.stackexchange.com/q/36403/91565

            – Kevin
            38 mins ago



















          • This is a very smart solution!

            – Panki
            12 hours ago






          • 2





            Is this method limited to commands that take only one argument? If cook takes two file arguments, and I have the_recipe1 and the_recipe2 (both of which are string variables), will this method still work?

            – Flux
            11 hours ago








          • 5





            @Flux You can do it with /dev/fd but that's beyond the scope of your initial question. But I think you'll find examples of that in unix.stackexchange.com/questions/tagged/file-descriptors

            – Gilles
            11 hours ago











          • This is not 100% portable, though it does come pretty close in practice: unix.stackexchange.com/q/36403/91565

            – Kevin
            38 mins ago

















          This is a very smart solution!

          – Panki
          12 hours ago





          This is a very smart solution!

          – Panki
          12 hours ago




          2




          2





          Is this method limited to commands that take only one argument? If cook takes two file arguments, and I have the_recipe1 and the_recipe2 (both of which are string variables), will this method still work?

          – Flux
          11 hours ago







          Is this method limited to commands that take only one argument? If cook takes two file arguments, and I have the_recipe1 and the_recipe2 (both of which are string variables), will this method still work?

          – Flux
          11 hours ago






          5




          5





          @Flux You can do it with /dev/fd but that's beyond the scope of your initial question. But I think you'll find examples of that in unix.stackexchange.com/questions/tagged/file-descriptors

          – Gilles
          11 hours ago





          @Flux You can do it with /dev/fd but that's beyond the scope of your initial question. But I think you'll find examples of that in unix.stackexchange.com/questions/tagged/file-descriptors

          – Gilles
          11 hours ago













          This is not 100% portable, though it does come pretty close in practice: unix.stackexchange.com/q/36403/91565

          – Kevin
          38 mins ago





          This is not 100% portable, though it does come pretty close in practice: unix.stackexchange.com/q/36403/91565

          – Kevin
          38 mins ago













          24














          One other way to use the process-substitution feature of the bash shell causes a FIFO to be created under /tmp or /var/tmp, or uses a named file descriptor (/dev/fd/*), depending on the operating system. The substitution syntax (<(cmd)) is replaced by the name of the FIFO or FD, and the command inside it is run in the background.



          cook <(printf '%sn' "${the_recipe}")


          The command cook now reads the content of the variable as if it were available in a file.



          This could also be used for more than one input file:



          cook <(printf '%sn' "${the_1st_recipe}") <(printf '%sn' "${the_2nd_recipe}")





          share|improve this answer





















          • 4





            Alternatively, cat <<<"$the_recipe" inside the process substitution.

            – Kusalananda
            11 hours ago






          • 5





            Note that process substitution is a ksh feature (now also supported by zsh and bash). Chances are cook will expect a text file, so you should probably make it '%sn' instead of '%s'. See also <(<<<$the_recipe) in zsh.

            – Stéphane Chazelas
            11 hours ago
















          24














          One other way to use the process-substitution feature of the bash shell causes a FIFO to be created under /tmp or /var/tmp, or uses a named file descriptor (/dev/fd/*), depending on the operating system. The substitution syntax (<(cmd)) is replaced by the name of the FIFO or FD, and the command inside it is run in the background.



          cook <(printf '%sn' "${the_recipe}")


          The command cook now reads the content of the variable as if it were available in a file.



          This could also be used for more than one input file:



          cook <(printf '%sn' "${the_1st_recipe}") <(printf '%sn' "${the_2nd_recipe}")





          share|improve this answer





















          • 4





            Alternatively, cat <<<"$the_recipe" inside the process substitution.

            – Kusalananda
            11 hours ago






          • 5





            Note that process substitution is a ksh feature (now also supported by zsh and bash). Chances are cook will expect a text file, so you should probably make it '%sn' instead of '%s'. See also <(<<<$the_recipe) in zsh.

            – Stéphane Chazelas
            11 hours ago














          24












          24








          24







          One other way to use the process-substitution feature of the bash shell causes a FIFO to be created under /tmp or /var/tmp, or uses a named file descriptor (/dev/fd/*), depending on the operating system. The substitution syntax (<(cmd)) is replaced by the name of the FIFO or FD, and the command inside it is run in the background.



          cook <(printf '%sn' "${the_recipe}")


          The command cook now reads the content of the variable as if it were available in a file.



          This could also be used for more than one input file:



          cook <(printf '%sn' "${the_1st_recipe}") <(printf '%sn' "${the_2nd_recipe}")





          share|improve this answer















          One other way to use the process-substitution feature of the bash shell causes a FIFO to be created under /tmp or /var/tmp, or uses a named file descriptor (/dev/fd/*), depending on the operating system. The substitution syntax (<(cmd)) is replaced by the name of the FIFO or FD, and the command inside it is run in the background.



          cook <(printf '%sn' "${the_recipe}")


          The command cook now reads the content of the variable as if it were available in a file.



          This could also be used for more than one input file:



          cook <(printf '%sn' "${the_1st_recipe}") <(printf '%sn' "${the_2nd_recipe}")






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 11 hours ago

























          answered 12 hours ago









          InianInian

          4,9951329




          4,9951329








          • 4





            Alternatively, cat <<<"$the_recipe" inside the process substitution.

            – Kusalananda
            11 hours ago






          • 5





            Note that process substitution is a ksh feature (now also supported by zsh and bash). Chances are cook will expect a text file, so you should probably make it '%sn' instead of '%s'. See also <(<<<$the_recipe) in zsh.

            – Stéphane Chazelas
            11 hours ago














          • 4





            Alternatively, cat <<<"$the_recipe" inside the process substitution.

            – Kusalananda
            11 hours ago






          • 5





            Note that process substitution is a ksh feature (now also supported by zsh and bash). Chances are cook will expect a text file, so you should probably make it '%sn' instead of '%s'. See also <(<<<$the_recipe) in zsh.

            – Stéphane Chazelas
            11 hours ago








          4




          4





          Alternatively, cat <<<"$the_recipe" inside the process substitution.

          – Kusalananda
          11 hours ago





          Alternatively, cat <<<"$the_recipe" inside the process substitution.

          – Kusalananda
          11 hours ago




          5




          5





          Note that process substitution is a ksh feature (now also supported by zsh and bash). Chances are cook will expect a text file, so you should probably make it '%sn' instead of '%s'. See also <(<<<$the_recipe) in zsh.

          – Stéphane Chazelas
          11 hours ago





          Note that process substitution is a ksh feature (now also supported by zsh and bash). Chances are cook will expect a text file, so you should probably make it '%sn' instead of '%s'. See also <(<<<$the_recipe) in zsh.

          – Stéphane Chazelas
          11 hours ago











          14














          It depends on the application's capabilities. It may or may not insist on a named file, and it may or may not insist on a seekable file.



          Anonymous pipe



          Some applications just read input from anywhere. Typically they default to reading from standard input. If you have the data in a string and you want to pass it to the application's standard input, there are a few ways. You can pass the information via a pipe:



          printf '%s' "$the_recipe" | cook     # passes $the_recipe exactly
          printf '%sn' "$the_recipe" | cook # passes $the_recipe plus a final newline


          Don't use echo here because depending on the shell, it might mangle backslashes.



          If the application insists on a file argument, it might accept - to mean standard input. This is a common convention, but not systematic.



          printf '%sn' "$the_recipe" | cook -


          If the application needs an actual file name, pass /dev/stdin to mean standard input.



          printf '%sn' "$the_recipe" | cook /dev/stdin


          For some applications, even this is not enough: they need a file name with certain properties, for example with a given extension, or they need a file name in a writable directory where they create temporary files. In such cases, you generally need a temporary file, although sometimes a named pipe is enough.



          Named pipe



          It's possible to give a pipe a name. I mention this for completeness, but it's rarely the most convenient way. It does avoid getting the data on disk. It's suitable if the application needs a file with constraints on the name, but doesn't need the file to be seekable.



          mkfifo named.pipe
          printf '%sn' "$the_recipe" >named.pipe & writer=$!
          cook named.pipe
          rm named.pipe
          wait "$writer"


          (Error checking omitted.)



          Temporary file



          If the application needs a seekable file, you need to create a temporary file. A seekable file is one where the application can go back and forth, reading arbitrary portions at a time. A pipe doesn't allow this: it needs to be read from start to finish, in sequence, without ever going backwards.



          Bash, ksh and zsh have a convenient syntax to pass a string as input via a temporary file. Note that they always append a newline to the string (even if there's already one).



          cook <<<"$the_recipe"


          With other shells, or if you want to control which directory contains the temporary file, you need to create the temporary file manually. Most unices provide a mktemp utility to create the temporary file securely. (Never use something like … >/tmp/temp.$$! It allows other programs, even running as other users, to hijack the file.) Here's a script that creates a temporary file and takes care of removing it if interrupted.



          tmp=
          trap 'rm -f "$tmp"' EXIT
          trap 'rm -f "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -f "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -f "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp)
          printf '%sn' "$the_recipe" >"$tmp"
          cook "$tmp"


          To choose where to create the temporary file, set the TMPDIR environment variable for the mktemp call. For example, to create the temporary file in the current directory rather than the default location for temporary files:



          tmp=$(TMPDIR="$PWD" mktemp)


          (Using $PWD rather than . gives you an absolute file name, which means you can safely call cd in your script without worrying that $tmp will no longer designate the same file.)



          If the application needs a file name with a certain extension, you need to create a temporary directory and create a file there. To create the temporary directory, use mktemp -d. Again, set the TMPDIR environment variable if you want to control where the temporary directory is created.



          tmp=
          trap 'rm -rf "$tmp"' EXIT
          trap 'rm -rf "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -rf "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -rf "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp -d)
          printf '%sn' "$the_recipe" >"$tmp/myfile.ext"
          cook "$tmp/myfile.ext"





          share|improve this answer
























          • I'm pretty sure you can use a here-doc as input, too (I think you might have to use <(cat <<END) or similar; it's years since I've done that).

            – Toby Speight
            8 hours ago
















          14














          It depends on the application's capabilities. It may or may not insist on a named file, and it may or may not insist on a seekable file.



          Anonymous pipe



          Some applications just read input from anywhere. Typically they default to reading from standard input. If you have the data in a string and you want to pass it to the application's standard input, there are a few ways. You can pass the information via a pipe:



          printf '%s' "$the_recipe" | cook     # passes $the_recipe exactly
          printf '%sn' "$the_recipe" | cook # passes $the_recipe plus a final newline


          Don't use echo here because depending on the shell, it might mangle backslashes.



          If the application insists on a file argument, it might accept - to mean standard input. This is a common convention, but not systematic.



          printf '%sn' "$the_recipe" | cook -


          If the application needs an actual file name, pass /dev/stdin to mean standard input.



          printf '%sn' "$the_recipe" | cook /dev/stdin


          For some applications, even this is not enough: they need a file name with certain properties, for example with a given extension, or they need a file name in a writable directory where they create temporary files. In such cases, you generally need a temporary file, although sometimes a named pipe is enough.



          Named pipe



          It's possible to give a pipe a name. I mention this for completeness, but it's rarely the most convenient way. It does avoid getting the data on disk. It's suitable if the application needs a file with constraints on the name, but doesn't need the file to be seekable.



          mkfifo named.pipe
          printf '%sn' "$the_recipe" >named.pipe & writer=$!
          cook named.pipe
          rm named.pipe
          wait "$writer"


          (Error checking omitted.)



          Temporary file



          If the application needs a seekable file, you need to create a temporary file. A seekable file is one where the application can go back and forth, reading arbitrary portions at a time. A pipe doesn't allow this: it needs to be read from start to finish, in sequence, without ever going backwards.



          Bash, ksh and zsh have a convenient syntax to pass a string as input via a temporary file. Note that they always append a newline to the string (even if there's already one).



          cook <<<"$the_recipe"


          With other shells, or if you want to control which directory contains the temporary file, you need to create the temporary file manually. Most unices provide a mktemp utility to create the temporary file securely. (Never use something like … >/tmp/temp.$$! It allows other programs, even running as other users, to hijack the file.) Here's a script that creates a temporary file and takes care of removing it if interrupted.



          tmp=
          trap 'rm -f "$tmp"' EXIT
          trap 'rm -f "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -f "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -f "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp)
          printf '%sn' "$the_recipe" >"$tmp"
          cook "$tmp"


          To choose where to create the temporary file, set the TMPDIR environment variable for the mktemp call. For example, to create the temporary file in the current directory rather than the default location for temporary files:



          tmp=$(TMPDIR="$PWD" mktemp)


          (Using $PWD rather than . gives you an absolute file name, which means you can safely call cd in your script without worrying that $tmp will no longer designate the same file.)



          If the application needs a file name with a certain extension, you need to create a temporary directory and create a file there. To create the temporary directory, use mktemp -d. Again, set the TMPDIR environment variable if you want to control where the temporary directory is created.



          tmp=
          trap 'rm -rf "$tmp"' EXIT
          trap 'rm -rf "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -rf "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -rf "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp -d)
          printf '%sn' "$the_recipe" >"$tmp/myfile.ext"
          cook "$tmp/myfile.ext"





          share|improve this answer
























          • I'm pretty sure you can use a here-doc as input, too (I think you might have to use <(cat <<END) or similar; it's years since I've done that).

            – Toby Speight
            8 hours ago














          14












          14








          14







          It depends on the application's capabilities. It may or may not insist on a named file, and it may or may not insist on a seekable file.



          Anonymous pipe



          Some applications just read input from anywhere. Typically they default to reading from standard input. If you have the data in a string and you want to pass it to the application's standard input, there are a few ways. You can pass the information via a pipe:



          printf '%s' "$the_recipe" | cook     # passes $the_recipe exactly
          printf '%sn' "$the_recipe" | cook # passes $the_recipe plus a final newline


          Don't use echo here because depending on the shell, it might mangle backslashes.



          If the application insists on a file argument, it might accept - to mean standard input. This is a common convention, but not systematic.



          printf '%sn' "$the_recipe" | cook -


          If the application needs an actual file name, pass /dev/stdin to mean standard input.



          printf '%sn' "$the_recipe" | cook /dev/stdin


          For some applications, even this is not enough: they need a file name with certain properties, for example with a given extension, or they need a file name in a writable directory where they create temporary files. In such cases, you generally need a temporary file, although sometimes a named pipe is enough.



          Named pipe



          It's possible to give a pipe a name. I mention this for completeness, but it's rarely the most convenient way. It does avoid getting the data on disk. It's suitable if the application needs a file with constraints on the name, but doesn't need the file to be seekable.



          mkfifo named.pipe
          printf '%sn' "$the_recipe" >named.pipe & writer=$!
          cook named.pipe
          rm named.pipe
          wait "$writer"


          (Error checking omitted.)



          Temporary file



          If the application needs a seekable file, you need to create a temporary file. A seekable file is one where the application can go back and forth, reading arbitrary portions at a time. A pipe doesn't allow this: it needs to be read from start to finish, in sequence, without ever going backwards.



          Bash, ksh and zsh have a convenient syntax to pass a string as input via a temporary file. Note that they always append a newline to the string (even if there's already one).



          cook <<<"$the_recipe"


          With other shells, or if you want to control which directory contains the temporary file, you need to create the temporary file manually. Most unices provide a mktemp utility to create the temporary file securely. (Never use something like … >/tmp/temp.$$! It allows other programs, even running as other users, to hijack the file.) Here's a script that creates a temporary file and takes care of removing it if interrupted.



          tmp=
          trap 'rm -f "$tmp"' EXIT
          trap 'rm -f "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -f "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -f "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp)
          printf '%sn' "$the_recipe" >"$tmp"
          cook "$tmp"


          To choose where to create the temporary file, set the TMPDIR environment variable for the mktemp call. For example, to create the temporary file in the current directory rather than the default location for temporary files:



          tmp=$(TMPDIR="$PWD" mktemp)


          (Using $PWD rather than . gives you an absolute file name, which means you can safely call cd in your script without worrying that $tmp will no longer designate the same file.)



          If the application needs a file name with a certain extension, you need to create a temporary directory and create a file there. To create the temporary directory, use mktemp -d. Again, set the TMPDIR environment variable if you want to control where the temporary directory is created.



          tmp=
          trap 'rm -rf "$tmp"' EXIT
          trap 'rm -rf "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -rf "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -rf "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp -d)
          printf '%sn' "$the_recipe" >"$tmp/myfile.ext"
          cook "$tmp/myfile.ext"





          share|improve this answer













          It depends on the application's capabilities. It may or may not insist on a named file, and it may or may not insist on a seekable file.



          Anonymous pipe



          Some applications just read input from anywhere. Typically they default to reading from standard input. If you have the data in a string and you want to pass it to the application's standard input, there are a few ways. You can pass the information via a pipe:



          printf '%s' "$the_recipe" | cook     # passes $the_recipe exactly
          printf '%sn' "$the_recipe" | cook # passes $the_recipe plus a final newline


          Don't use echo here because depending on the shell, it might mangle backslashes.



          If the application insists on a file argument, it might accept - to mean standard input. This is a common convention, but not systematic.



          printf '%sn' "$the_recipe" | cook -


          If the application needs an actual file name, pass /dev/stdin to mean standard input.



          printf '%sn' "$the_recipe" | cook /dev/stdin


          For some applications, even this is not enough: they need a file name with certain properties, for example with a given extension, or they need a file name in a writable directory where they create temporary files. In such cases, you generally need a temporary file, although sometimes a named pipe is enough.



          Named pipe



          It's possible to give a pipe a name. I mention this for completeness, but it's rarely the most convenient way. It does avoid getting the data on disk. It's suitable if the application needs a file with constraints on the name, but doesn't need the file to be seekable.



          mkfifo named.pipe
          printf '%sn' "$the_recipe" >named.pipe & writer=$!
          cook named.pipe
          rm named.pipe
          wait "$writer"


          (Error checking omitted.)



          Temporary file



          If the application needs a seekable file, you need to create a temporary file. A seekable file is one where the application can go back and forth, reading arbitrary portions at a time. A pipe doesn't allow this: it needs to be read from start to finish, in sequence, without ever going backwards.



          Bash, ksh and zsh have a convenient syntax to pass a string as input via a temporary file. Note that they always append a newline to the string (even if there's already one).



          cook <<<"$the_recipe"


          With other shells, or if you want to control which directory contains the temporary file, you need to create the temporary file manually. Most unices provide a mktemp utility to create the temporary file securely. (Never use something like … >/tmp/temp.$$! It allows other programs, even running as other users, to hijack the file.) Here's a script that creates a temporary file and takes care of removing it if interrupted.



          tmp=
          trap 'rm -f "$tmp"' EXIT
          trap 'rm -f "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -f "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -f "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp)
          printf '%sn' "$the_recipe" >"$tmp"
          cook "$tmp"


          To choose where to create the temporary file, set the TMPDIR environment variable for the mktemp call. For example, to create the temporary file in the current directory rather than the default location for temporary files:



          tmp=$(TMPDIR="$PWD" mktemp)


          (Using $PWD rather than . gives you an absolute file name, which means you can safely call cd in your script without worrying that $tmp will no longer designate the same file.)



          If the application needs a file name with a certain extension, you need to create a temporary directory and create a file there. To create the temporary directory, use mktemp -d. Again, set the TMPDIR environment variable if you want to control where the temporary directory is created.



          tmp=
          trap 'rm -rf "$tmp"' EXIT
          trap 'rm -rf "$tmp"; trap "" HUP; kill -INT $$' HUP
          trap 'rm -rf "$tmp"; trap "" INT; kill -INT $$' INT
          trap 'rm -rf "$tmp"; trap "" TERM; kill -INT $$' TERM
          tmp=$(mktemp -d)
          printf '%sn' "$the_recipe" >"$tmp/myfile.ext"
          cook "$tmp/myfile.ext"






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 11 hours ago









          GillesGilles

          542k12810961615




          542k12810961615













          • I'm pretty sure you can use a here-doc as input, too (I think you might have to use <(cat <<END) or similar; it's years since I've done that).

            – Toby Speight
            8 hours ago



















          • I'm pretty sure you can use a here-doc as input, too (I think you might have to use <(cat <<END) or similar; it's years since I've done that).

            – Toby Speight
            8 hours ago

















          I'm pretty sure you can use a here-doc as input, too (I think you might have to use <(cat <<END) or similar; it's years since I've done that).

          – Toby Speight
          8 hours ago





          I'm pretty sure you can use a here-doc as input, too (I think you might have to use <(cat <<END) or similar; it's years since I've done that).

          – Toby Speight
          8 hours ago


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Unix & Linux Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f505828%2fhow-to-pass-a-string-to-a-command-that-expects-a-file%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          How to label and detect the document text images

          Vallis Paradisi

          Tabula Rosettana