script bash lire pipe ou argument

Je veux que mon script lise une chaîne à partir de stdin, si elle est diffusée, ou à partir d’un argument. Donc, je veux d’abord vérifier si du texte est diffusé et sinon, utiliser un argument en entrée. Mon code ressemble à ceci:

value=$(cat) # read from stdin if [ "$pipe" != "" ]; then #check if pipe is not empty #Do something with pipe ssortingng else #Do something with argument ssortingng fi 

Le problème est quand il n’est pas diffusé, alors le script s’arrêtera et attendra “ctrl d” et je ne le veux pas. Des suggestions sur la façon de résoudre ce problème?

Merci d’avance. / Tomas

Qu’en est-il de vérifier l’argument en premier?

 if (($#)) ; then process "$1" else cat | process fi 

Ou bien, profitez simplement du même comportement de cat :

 cat "$@" | process 

Si vous avez seulement besoin de savoir s’il s’agit d’un canal ou d’ une redirection, il devrait suffire de déterminer si stdin est un terminal ou non:

 if [ -t 0 ]; then # stdin is a tty: process command line else # stdin is not a tty: process standard input fi 

[ (alias test ) avec -t est équivalent à la fonction libc isatty() . Ce qui précède fonctionnera avec les deux something | myscript something | myscript et myscript < infile . C'est la solution la plus simple, en supposant que votre script est destiné à une utilisation interactive.

La commande [ est une commande intégrée à bash et à d'autres shells, et [ / test avec -t étant dans POSIX , elle est également portable (ne pas s'appuyer sur les fonctionnalités des utilitaires Linux, bash ou GNU).

Il y a un cas de bord, test -t renvoie également false si le descripteur de fichier n'est pas valide, mais il faudra un peu d'adversité pour arranger cela. test -e le détectera, bien que vous ayez un nom de fichier tel que /dev/stdin à utiliser.

La commande POSIX tty peut également être utilisée et gère l'adversité ci-dessus. Il imprimera le nom du périphérique tty et retournera 0 si stdin est un terminal, et affichera "not a tty" et renverra 1 dans les autres cas:

 if tty >/dev/null ; then # stdin is a tty: process command line else # stdin is not a tty: process standard input fi 

(avec GNU tty , vous pouvez utiliser tty -s pour un fonctionnement silencieux)

Une manière moins portable, bien que certainement acceptable sur un Linux typique, est d'utiliser GNU stat avec son spécificateur de format %F , cela retourne le texte "fichier spécial de personnage", "fifo" et "fichier régulier" dans les cas de terminal, pipe et redirection respectivement. stat nécessite un nom de fichier, vous devez donc fournir un fichier spécialement nommé de la forme /dev/stdin , /dev/fd/0 ou /proc/self/fd/0 et utiliser -L pour poursuivre les liens symboliques:

 stat -L -c "%F" /dev/stdin 

C'est probablement le meilleur moyen de gérer une utilisation non interactive (car vous ne pouvez pas faire d'hypothèses à ce moment-là) ou de détecter un canal réel (FIFO) distinct de la redirection.

Il y a un léger piège avec %F en ce sens que vous ne pouvez pas l'utiliser pour faire la différence entre un terminal et certains autres fichiers de périphériques, par exemple /dev/zero ou /dev/null qui sont aussi des "fichiers spéciaux". . Une solution imprécise consiste à utiliser %t pour signaler le type de périphérique sous-jacent (majeur, en hexadécimal), en supposant que vous connaissiez les plages de numéros de périphériques tty sous-jacentes ... et cela dépend si vous utilisez des ptys de style BSD , ou si vous êtes sur la console, entre autres. Dans le cas simple, %t sera 0 pour un tube ou une redirection d'un fichier normal (non spécial).

Des solutions plus générales à ce type de problème consistent à utiliser les read de bash avec un timeout ( read -t 0 ... ) ou les E / S non bloquantes avec GNU dd ( dd iflag=nonblock ).

Ce dernier vous permettra de détecter le manque d’entrée sur stdin, dd retournera un code de sortie de 1 s’il n’ya rien de prêt à lire. Cependant, ils conviennent mieux à des boucles d'interrogation non bloquantes qu'à une vérification unique: il existe une condition de concurrence lorsque vous démarrez plusieurs processus dans un pipeline, comme vous pouvez le lire avant qu'une autre ne soit écrite.

Il est plus facile de vérifier les arguments de la ligne de commande d’abord et de revenir à stdin si aucun argument. Shell Parameter Expansion est un raccourci plutôt que le if-else:

 value=${*:-`cat`}