1

Bash allows for piping to stdin from another command in this way...

$ ls /bin/aud* | cat
/bin/audacity
/bin/audiocompose
/bin/audiosend
...

...and this way as well:

$ cat <(ls /bin/aud*)
/bin/audacity
/bin/audiocompose
/bin/audiosend
...

Yet when I tried the same patterns to send a query to SQLite, I got this from the first form...

$ echo "select count(*) from urls;" | \
    sqlite3 ~/.config/google-chrome/Default/History
5983

...but this error on the second:

$ sqlite3 ~/.config/google-chrome/Default/History \
   <(echo "select count(*) from urls;")
Error: near "/": syntax error

This was surprising... The SQL statement is not interpolated or messed up by the shell:

$ echo "select count(*) from urls;"
echo "select count(*) from urls;"

And it's not about the echo either - it can definitely be used in redirecting:

$ cat <(echo Foo)
Foo

All I can think of is that somehow the path to the database file is misinterpreted and passed-in as also the SQL statement... (that's the only place containing a '/' - the only explanation for a 'syntax error near /').

Why, though? Any ideas?

4

The second form of I/O redirection (<(cmd)) simply doesn't behave the same way as the first form (cmd | other-cmd).

The first connects the output of cmd to the input of other-cmd, but the second substitutes either a /dev/fd path or a named pipe path in for the command. The standard output of cmd is tied to the other end of that pipe, but this only appears equivalent with commands like cat which will either read from stdin or from a file path. sqlite3 does not behave that way, so it exposes the difference between the two forms of I/O redirection.

sqlite3 expects optional SQL statements after the DB path, so it tries to parse this substituted path as SQL and fails.

Incidentally, this means that you don't need the I/O redirection at all. This command does what you're wanting more efficiently than either form you've tried:

$ sqlite3 ~/.config/google-chrome/Default/History "select count(*) from urls"

Note that you don't need the statement-terminating semicolon when passing a single SQL statement to sqlite3 as a command line parameter.

  • 2
    Note however you can get it working by doing other-cmd < <(cmd) – Patrick Jun 8 '16 at 4:29
  • @Patrick: Your comment is the perfect addition to Warren's answer - it's crystal clear now. Thanks, guys. – ttsiodras Jun 8 '16 at 6:35
1
$ echo <(echo "hi")
/dev/fd/63

/dev/fd/63 is not SQL, therefore sqlite3 fails with the indicated error message. cat by contrast is pretty good at reading files (or also from standard input). The named pipe or /dev/fd file of the <(list) construct created is not standard input.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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