232

Is there a way to effectively do this in bash:

/my/bash/script < echo 'This string will be sent to stdin.'

I'm aware that I could pipe the output from the echo such as this:

echo 'This string will be piped to stdin.' | /my/bash/script
5
  • 3
    What do you mean by effectively, why isn't pipe a way to do this?
    – Andy
    Commented Jun 30, 2011 at 21:10
  • Both of those commands you listed should do exactly the same thing. What problem are you having? Commented Jun 30, 2011 at 21:11
  • 10
    @Flimzy: afaik, the first one won't work as expected, it'll try to open a file called echo
    – Andy
    Commented Jun 30, 2011 at 21:13
  • Oh right. So what's wrong with the second form? Commented Jun 30, 2011 at 21:17
  • 2
    @Flimzy: besides, the > redirection form will open a file descriptor as fd 0 (stdin), whereas | opens starts a child process and attaches it's stdout (fd 1) to the other process's stdin. This fact can have non-trivial consequences (think about sharing environment variables?)
    – sehe
    Commented Jun 30, 2011 at 21:31

8 Answers 8

356

You can use one-line heredoc

cat <<< "This is coming from the stdin"

the above is the same as

cat <<EOF
This is coming from the stdin
EOF

or you can redirect output from a command, like

diff <(ls /bin) <(ls /usr/bin)

or you can read as

while read line
do
   echo =$line=
done < some_file

or simply

echo something | read param
13
  • 1
    And how to input binary values in this way? Without using the pipe (I know it can be done with the pipe as follows: echo -e "\x01\x02..." | ./script)
    – cprcrack
    Commented Dec 3, 2012 at 2:25
  • 1
    @jm666 sad thing is I learned yesterday if you use a bash alias, you just use the form command_alias <<< "stdin string", otherwise it will say command not found Commented Feb 12, 2014 at 17:26
  • 1
    @mekb takling about your examples / nothing. But imagine sed 's/x/y/' <<<'text'. Now the sed reading from its stdin the word text and outputs teyt. So, now here IS a difference. The exmple commands in the answer are just examples. You can replace the cat with any program reading from the STDIN.
    – clt60
    Commented Jul 8, 2021 at 11:43
  • 2
    A one-line 'here doc' is called a 'here string'. Commented Mar 5, 2023 at 21:48
  • 1
    Unless you want to calculate a hash or base64 off stdin :) Ask me how I found out about that extra character.
    – Kentzo
    Commented Jun 12, 2023 at 22:45
81

You were close

/my/bash/script <<< 'This string will be sent to stdin.'

For multiline input, here-docs are suited:

/my/bash/script <<STDIN -o other --options
line 1
line 2
STDIN

Edit To the comments:

To achieve binary input, say

xxd -r -p <<BINARY | iconv -f UCS-4BE -t UTF-8 | /my/bash/script
0000 79c1 0000 306f 0000 3061 0000 3093 0000 3077 0000 3093 0000 304b 0000 3093 0000 3077 0000 3093 0000 306a 0000 8a71 0000 306b 0000 30ca 0000 30f3 0000 30bb
0000 30f3 0000 30b9 0000 3092 0000 7ffb 0000 8a33 0000 3059 0000 308b 0000 3053 0000 3068 0000 304c 0000 3067 0000 304d 0000 000a
BINARY

If you substitute cat for /my/bash/script (or indeed drop the last pipe), this prints:

私はちんぷんかんぷんな話にナンセンスを翻訳することができ

Or, if you wanted something a little more geeky:

0000000: 0000 0000 bef9 0e3c 59f8 8e3c 0a71 d63c  .......<Y..<.q.<
0000010: c6f2 0e3d 3eaa 323d 3a5e 563d 090e 7a3d  ...=>.2=:^V=..z=
0000020: 7bdc 8e3d 2aaf a03d b67e b23d c74a c43d  {..=*..=.~.=.J.=
0000030: 0513 d63d 16d7 e73d a296 f93d a8a8 053e  ...=...=...=...>
0000040: 6583 0e3e 5a5b 173e 5b30 203e 3d02 293e  e..>Z[.>[0 >=.)>
0000050: d4d0 313e f39b 3a3e 6f63 433e 1c27 4c3e  ..1>..:>ocC>.'L>
0000060: cde6 543e 59a2 5d3e 9259 663e 4d0c 6f3e  ..T>Y.]>.Yf>M.o>
0000070: 60ba 773e cf31 803e ee83 843e 78d3 883e  `.w>.1.>...>x..>
0000080: 5720 8d3e 766a 913e beb1 953e 1cf6 993e  W .>vj.>...>...>
0000090: 7a37 9e3e c275 a23e dfb0 a63e bce8 aa3e  z7.>.u.>...>...>
00000a0: 441d af3e 624e b33e 017c b73e 0ca6 bb3e  D..>bN.>.|.>...>
00000b0: 6fcc bf3e 15ef c33e e90d c83e d728 cc3e  o..>...>...>.(.>
00000c0: c93f d03e ac52 d43e 6c61 d83e f36b dc3e  .?.>.R.>la.>.k.>
00000d0: 2f72 e03e 0a74 e43e 7171 e83e 506a ec3e  /r.>.t.>qq.>Pj.>
00000e0: 945e f03e 274e f43e f738 f83e f11e fc3e  .^.>'N.>.8.>...>
00000f0: 0000 003f 09ee 013f 89d9 033f 77c2 053f  ...?...?...?w..?
0000100: caa8 073f 788c 093f 776d 0b3f be4b 0d3f  ...?x..?wm.?.K.?
0000110: 4427 0f3f 0000 113f e8d5 123f f3a8 143f  D'.?...?...?...?
0000120: 1879 163f 4e46 183f 8d10 1a3f cad7 1b3f  .y.?NF.?...?...?
0000130: fe9b 1d3f 1f5d 1f3f 241b 213f 06d6 223f  ...?.].?$.!?.."?
0000140: bb8d 243f 3a42 263f 7cf3 273f 78a1 293f  ..$?:B&?|.'?x.)?
0000150: 254c 2b3f 7bf3 2c3f 7297 2e3f 0138 303f  %L+?{.,?r..?.80?
0000160: 22d5 313f ca6e 333f                      ".1?.n3?

Which is the sines of the first 90 degrees in 4byte binary floats

7
  • And how to input binary values in this way?
    – cprcrack
    Commented Dec 3, 2012 at 2:26
  • I'd use xxd -r (or od) to filter the HERE document
    – sehe
    Commented Dec 3, 2012 at 8:29
  • Could you explain it with an example? I didn't manage to do it.
    – cprcrack
    Commented Dec 3, 2012 at 17:59
  • 1
    see edited answer. The point is to not include raw binary data in your script, but instead filter it through a program like xxd
    – sehe
    Commented Dec 3, 2012 at 21:54
  • What is the point of doing: "/my/bash/script <<< 'This string will be sent to stdin.'" when you can directly say: "/my/bash/script 'This string will be sent to stdin.'" ? Commented May 16, 2014 at 0:55
25

Solution

You want to (1) create stdout output in one process (like echo '…') and (2) redirect that output to stdin input of another process but (3) without the use of the bash pipe mechanism. Here's a solution that matches all three conditions:

/my/bash/script < <(echo 'This string will be sent to stdin.')

The < is normal input redirection for stdin. The <(…) is bash process substitution. Roughly it creates a /dev/fd/… file with the output of the substituting command and passes that filename in place of the <(…), resulting here for example in script < /dev/fd/123. For details, see this answer.

Comparison with other solutions

  • A one-line heredoc sent to stdin script <<< 'string' only allows to send static strings, not the output of other commands.

  • Process substitution alone, such as in diff <(ls /bin) <(ls /usr/bin), does not send anything to stdin. Instead, the process output is saved into a file, and its path is passed as a command line argument. For the above example, this is equivalent to diff /dev/fd/10 /dev/fd/11, a command where diff receives no input from stdin.

Use cases

I like that, unlike the pipe mechanism, the < <(…) mechanism allows to put the command first and all input after it, as is the standard for input from command line options.

However, beyond commandline aesthetics, there are some cases where a pipe mechanism cannot be used. For example, when a specific command like ssh or scp is expected as argument of another command, such as in this example with sshpass.

4
  • 1
    Interesting alternative. Does this happen to be POSIX compliant unlike <<<?
    – ohmu
    Commented May 23, 2020 at 16:34
  • 1
    No, this is not POSIX; process substitutions are Bash only, just like here strings.
    – tripleee
    Commented Aug 9, 2021 at 6:04
  • Any idea how the performance of this compares to pipes?
    – jspencer
    Commented Nov 16, 2021 at 22:03
  • 1
    You can also use the one-line heredoc with a variable - I use it all the time with captured output from another command when I don't want to repeatedly rerun that command Commented Jul 21, 2023 at 7:31
3

You can also use read like this

echo "enter your name"
read name
echo $name
2
cat | /my/bash/script

Enables one to type multiple lines into a program, without that input being saved in history, nor visible in ps. Finish with a newline then Ctrl + D to end cat.

0
0

I know this is an old question but it is a question I am asked regularly.

I use:

/my/bash/script $(echo 'This string will be sent to stdin.')

Bash runs the command in a subshell and passes the output to stdin of the original command.

2
  • That doesn't actually pass your string via stdin. I passes the stdout of the subshell as command line arguments to your script. It's no different from running /my/bash/script This string will be sent to stdin..
    – ohmu
    Commented Oct 3, 2023 at 19:41
  • if the string you want to pass to the first command, is not a static string, and you need another command to generate the string, then it works well, and is very different to just typing the string, because you can not just type a dynamic string. Commented Oct 3, 2023 at 22:14
0

I needed to run an operation that required keystrokes (there was no --quiet or --force). I did something like this:

$ read x <<< "x-value
> "
$ echo $x
x-value
-4

aliases can and can't process piped stdin...

Here we create 3 lines of output

$ echo -e "line 1\nline 2\nline 3"
line 1
line 2
line 3

We then pipe the output to stdin of the sed command to put them all on one line

$ echo -e "line 1\nline 2\nline 3" |  sed -e ":a;N;\$!ba ;s?\n? ?g"
line 1 line 2 line 3

If we define an alias of the same sed command

$ alias oline='sed -e ":a;N;\$!ba ;s?\n? ?g"'

We can pipe the output to the stdin of the alias and it behaves exactly the same

$ echo -e "line 1\nline 2\nline 3" |  oline
line 1 line 2 line 3

The problem arises when we try to define the alias as a function

$ alias oline='function _oline(){ sed -e ":a;N;\$!ba ;s?\n? ?g";}_oline'

Defining the alias as a funstion breaks the pipe

$ echo -e "line 1\nline 2\nline 3" |  oline
>
1
  • 1
    Firstly, this does not answer the question - maybe you answered the wrong question? Secondly, why would you ever define a function inside an alias? You should just do function oline() { sed -e ":a;N;\$!ba ;s?\n? ?g"; }. Thirdly, this sed would be a lot more understandable with awk: awk -F '\n' 'ORS=" " { print } END { printf "\n"}' Commented Jun 23, 2020 at 21:42

Not the answer you're looking for? Browse other questions tagged or ask your own question.