Comment lire une entrée multiligne de stdin en variable et comment en imprimer une en shell (sh, bash)?
Question
Ce que je veux faire est le suivant:
- lit plusieurs lignes à partir de
stdin
dans la variableA
- effectuer diverses opérations sur
\n
- canaliser
\r
sans perdre les symboles de délimiteur (\t
,read
,cat
, etc.) vers une autre commande
Le problème actuel est que je ne peux pas le lire avec la commande <=> car il arrête la lecture à la nouvelle ligne.
Je peux lire stdin avec <=>, comme ceci:
my_var=`cat /dev/stdin`
, mais je ne sais pas comment l’imprimer. De sorte que la nouvelle ligne, l'onglet et d'autres délimiteurs soient toujours présents.
Mon exemple de script ressemble à ceci:
#!/usr/local/bin/bash
A=`cat /dev/stdin`
if [ ${#A} -eq 0 ]; then
exit 0
else
cat ${A} | /usr/local/sbin/nextcommand
fi
La solution
Cela fonctionne pour moi:
myvar=`cat`
echo "$myvar"
Les guillemets autour de $myvar
sont importants.
Autres conseils
Dans Bash, il existe un autre moyen: man bash
mentionne:
La substitution de commande
$(cat file)
peut être remplacée par l'équivalent mais plus rapidement$(< file)
.
$ myVar=$(</dev/stdin)
hello
this is test
$ echo "$myVar"
hello
this is test
tee fait le travail
#!/bin/bash
myVar=$(tee)
Oui, ça marche aussi pour moi. Merci.
myvar=`cat`
est identique à
myvar=`cat /dev/stdin`
Bien oui. A partir de la bash
page de manuel:
Caractères entre guillemets préserve la valeur littérale de tous caractères entre guillemets, à l'exception de $, `, \ et lorsque l'extension de l'historique est activée, !. Les personnages $ et ` conservez leur signification particulière entre guillemets doubles.
Si vous vous souciez de conserver les retours à la fin à la fin de la sortie, utilisez ceci:
myVar=$(cat; echo x)
myVar=${myVar%x}
printf %s "$myVar"
Ceci utilise le truc de ici .
[mise à jour]
Cette affectation sera suspendue indéfiniment s'il n'y a rien dans le tuyau ...
var="$(< /dev/stdin)"
Nous pouvons toutefois éviter cela en faisant un délai d'attente read
pour le premier caractère. S'il expire, le code de retour sera supérieur à 128 et nous saurons que le canal STDIN (a.k.a /dev/stdin
) est vide.
Sinon, nous obtenons le reste de STDIN par ...
- définir
IFS
sur NULL pour la-r
commande - désactiver les sorties avec
-d ''
- élimination du délimiteur de lecture avec
var="$(command ...)"
. - et enfin, en ajoutant cela au personnage que nous avons obtenu initialement
Ainsi ...
__=""
_stdin=""
read -N1 -t1 __ && {
(( $? <= 128 )) && {
IFS= read -rd '' _stdin
_stdin="$__$_stdin"
}
}
Cette technique évite d'utiliser $()
la substitution de commande qui, de par sa conception, supprime toujours les retours à la ligne.
Si vous préférez remplacer les commandes, vous pouvez ajouter un ou plusieurs caractères de délimitation à la sortie située à l'intérieur de $(parens)
pour les conserver à la fin de la ligne, puis les supprimer à l'extérieur.
Par exemple (remarque ${braces}
dans la première commande et <=> en seconde) ...
_stdin="$(awk '{print}; END {print "|||"}' /dev/stdin)"
_stdin="${_stdin%|||}"