6

Script:

#!/bin/sh
#
# reads stdin/file and copies it to clipboard
# clears it after 30s
#
cat "${1:-/dev/stdin}" | timeout 30 xclip -i -selection clipboard -r -verbose &>/dev/null &

I can see that only stdin does not work (with bash it works on stdin/file).
P.S. verbose is used to make xclip not daemonize.

10
  • That won't work with /dev/stdin even with bash. Since you're running with the pipeline put in the background (terminated with &) cat /dev/stdin will either have its stdin redirected from /dev/null (when running in a script) or will be stopped by a SIGTTIN signal (when running in an interactive shell).
    – user313992
    Jun 6, 2019 at 22:39
  • you sure about the second? because it works (bash) in my terminal echo 123 | script. Is there anyway I can do what I want to do?
    – droso
    Jun 6, 2019 at 22:49
  • Look at end of the pipeline in your Q. There's a & at the end -- the shell won't treat it as decoration ;-)
    – user313992
    Jun 6, 2019 at 22:51
  • of course not but whole script will work in the foreground (because of -verbose but -verbose is needed to make timeout work)
    – droso
    Jun 6, 2019 at 22:58
  • Try this in your script: exec 3<"${1:-/dev/stdin}"; cat <&3 | ... &.
    – user313992
    Jun 6, 2019 at 22:59

3 Answers 3

10

&> is a bashism, you will have to change it to >/dev/null 2>&1 for POSIX shells

1
  • 1
    Now stdout is suppressed like it should be thank you BUT stdin is still not working ($1 works). Also I had to use >/dev/null 2>&1
    – droso
    Jun 6, 2019 at 22:22
7

[this answer is about asynchronous pipelines in scripts; for the deprecated &> bash operator and why you should always use >output 2>&1 instead, refer to obsolete and deprecated syntax]

#! /bin/sh
cat "${1:-/dev/stdin}" | ... &

Here you have a pipeline running asynchronously (because terminated by &), started from a script, ie is from a shell with the job control disabled.

According to the standard:

command1 & [command2 & ... ]

The standard input for an asynchronous list, before any explicit redirections are performed, shall be considered to be assigned to a file that has the same properties as /dev/null.

The problem is that dash, ksh, mksh, yash, etc intepret "asynchronous list" as any command, including a pipeline, and will redirect the stdin of the first command from /dev/null:

$ echo foo | dash -c 'cat | tr fo FO & echo DONE'
DONE
$ echo | dash -c 'readlink /proc/self/fd/0 | cat & echo DONE'
DONE
/dev/null

But bash will only interpret it as "simple command" and will only redirect its stdin from /dev/null when it's not part of a pipeline:

$ echo foo | bash -c 'cat | tr fo FO & echo DONE'
DONE
FOO
$ echo | bash -c 'readlink /proc/self/fd/0 | cat & echo DONE'
DONE
pipe:[69872]
$ echo | bash -c 'readlink /proc/self/fd/0 & echo DONE'
DONE
/dev/null
$ bash -c 'cat | tr a A & echo DONE'
DONE
cat: -: Input/output error

zsh will only redirect it from /dev/null when the original stdin is a tty, not when it's other kind of file:

$ zsh -c 'readlink /proc/self/fd/0 &' </dev/tty
/dev/null
$ zsh -c 'readlink /proc/self/fd/0 &' </dev/zero
/dev/zero

A workaround which works in all shells is to duplicate the stdin into another file descriptor, and redirect the stdin of the first command from it:

#! /bin/sh
exec 3<"${1:-/dev/stdin}"
cat <&3 | timeout 30 xclip -i -selection clipboard -verbose -r >/dev/null 2>&1 &
1
  • 1
    nitpick: in the POSIX grammar/terminology, a simple command (like readlink /proc/self/fd/0) is a pipeline (with one element) and readlink /proc/self/fd/0 | cat a pipeline with two elements. In bash and POSIX shells (but not zsh), a & affects an and-or list, not just the last pipeline in the and-or list. See also the current discussion on the austin-group ML about austingroupbugs.net/view.php?id=1254 Aug 10, 2019 at 6:42
7

dash positioned as POSIX standard. POSIX specified only [n]> redirection. But bash introduces many own features. &> is one of them and means output descriptors (stderr and stdout).

You should read article about bash and dash compatibility.

Maybe you get helpful checkbashisms utility which can helps to find bash-specific instructions in your scripts.

2
  • 1
    &> is only stdout and stderr, not "all" file descriptors. (It's also considered obsolescent and not suggested for use, even in bash). Jun 7, 2019 at 18:58
  • @CharlesDuffy Thank's for correction. I've just fixed it in the own answer! Jun 7, 2019 at 20:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .