Dans un script shell ...
Comment capturer stdin dans une variable sans supprimer les sauts de ligne de fin?
En ce moment, j'ai essayé:
var=`cat`
var=`tee`
var=$(tee)
Dans tous les cas, $var
il n'y aura pas de nouvelle ligne de fin du flux d'entrée. Merci.
AUSSI: S'il n'y a pas de nouvelle ligne de fin dans l'entrée, la solution ne doit pas en ajouter une .
MISE À JOUR À LA LUMIÈRE DE LA RÉPONSE ACCEPTÉE:
La solution finale que j'ai utilisée dans mon code est la suivante:
function filter() {
#do lots of sed operations
#see https://github.com/gistya/expandr for full code
}
GIT_INPUT=`cat; echo x`
FILTERED_OUTPUT=$(printf '%s' "$GIT_INPUT" | filter)
FILTERED_OUTPUT=${FILTERED_OUTPUT%x}
printf '%s' "$FILTERED_OUTPUT"
Si vous souhaitez voir le code complet, veuillez consulter la page github pour expandr , un petit script shell de filtre d'extension de mot-clé git open-source que j'ai développé à des fins de sécurité de l'information. Selon les règles définies dans les fichiers .gitattributes (qui peuvent être spécifiques à une branche) et git config , git redirige chaque fichier via le script shell expandr.sh chaque fois qu'il est entré ou sorti du référentiel. (C'est pourquoi il était essentiel de conserver les nouvelles lignes ou leur absence.) Cela vous permet de nettoyer les informations sensibles et d'échanger différents ensembles de valeurs spécifiques à l'environnement pour les branches de test, de transfert et actives.
filter
prendstdin
- il courtsed
. Vous attrapezstdin
dans$GIT_INPUT
puis imprimer ce retour àstdout
plus d' un tuyau pourfilter
et attraper sonstdout
dans$FILTERED_OUTPUT
puis l' imprimer retour àstdout
. Les 4 lignes en bas de votre exemple ci - dessus pourraient être remplacés par ceci:filter
. Aucune infraction ne signifie ici, c'est juste que ... vous travaillez trop dur. Vous n'avez pas besoin des variables shell la plupart du temps - dirigez simplement l'entrée au bon endroit et transmettez-la.filter
, cela ajoutera des caractères de nouvelle ligne aux extrémités de tous les flux d'entrée qui ne se terminaient pas initialement par des nouvelles lignes. En fait, à l'origine, je venais de le faire,filter
mais je suis tombé sur ce problème qui m'a conduit à cette solution car ni "toujours ajouter des nouvelles lignes" ni "toujours supprimer les nouvelles lignes" ne sont des solutions acceptables.sed
fera probablement la nouvelle ligne supplémentaire - mais vous devriez gérer celafilter
avec pas tout le reste. Et toutes ces fonctions que vous avez font essentiellement la même chose - ased s///
. Vous utilisez le shell pour diriger les données qu'il a enregistrées dans sa mémoiresed
afin desed
remplacer ces données par d'autres données que le shell a stockées dans sa mémoire afin desed
pouvoir les rediriger vers le shell. Pourquoi pas juste[ "$var" = "$condition" ] && var=new_value
? Je ne reçois pas non plus les tableaux - stockez-vous le nom du tableau dans[0]
puis l'utilisersed
pour le remplacer par la valeur dans[1]
? Peut-être discuter?filter
? Cela fonctionne parfaitement tel quel. En ce qui concerne le fonctionnement du code sur mon lien et pourquoi je l'ai configuré comme je l'ai fait, oui, parlons-en dans un salon de discussion.Réponses:
Les sauts de ligne de fin sont supprimés avant que la valeur ne soit stockée dans la variable. Vous voudrez peut-être faire quelque chose comme:
et utiliser à la
${var%x}
place de$var
. Par exemple:Notez que cela résout le problème de retour à la ligne, mais pas celui d'octet nul (si l'entrée standard n'est pas du texte), car selon la substitution de commande POSIX :
Mais les implémentations de shell peuvent conserver des octets nuls.
la source
Vous pouvez utiliser le
read
intégré pour accomplir ceci:Pour qu'un script lise STDIN, ce serait simplement:
Je ne sais pas dans quels coquilles cela fonctionnera cependant. Mais fonctionne bien dans bash et zsh.
la source
-d
la substitution de processus (<(...)
) ne sont portables; ce code ne fonctionnera pasdash
, par exemple.-d
, c'est pourquoi j'ai mis l'avertissement en bas. L'OP ne spécifie pas le shell.dash
. Vous utilisez simplement<<HEREDOC\n$(gen input)\nHEREDOC\n
- dansdash
- qui utilise des tuyaux pour les heredocs de la même manière que les autres shells les utilisent pour la substitution de processus - cela ne fait aucune différence. Laread -d
chose consiste simplement à spécifier un délimiteur - vous pouvez faire de même une douzaine de façons - assurez-vous simplement à ce sujet. Bien que vous ayez besoin d'un peu de queuegen input
.IFS=''
n'est probablement pas nécessaire. Il est conçu pour queread
les espaces ne s'effondrent pas. Mais quand il lit dans une seule variable, cela n'a aucun effet (que je me souvienne). Mais je me sens plus en sécurité en le laissant :-)Vous pouvez faire comme:
Quoi que vous fassiez
$var
disparaît dès que vous sortez de ce{ current shell ; }
groupe de toute façon. Mais cela pourrait aussi fonctionner comme:la source
$var
dans le{ ... }
groupement, ce n'est pas toujours possible. Par exemple, si cette commande est exécutée à l'intérieur d'une boucle et qu'il faut en$var
dehors de la boucle.{}
accolades .Il est vrai - et il est explicitement indiqué dans la réponse - que la valeur$var
est très susceptible de disparaître complètement lorsque le{ current shell; }
groupe est fermé. Y a-t-il une manière plus explicite de le dire que, quoi que vous fassiez$var
disparaisse ...?input | sed "s/'"'/&"&"&/g;s/.*/process2 '"'-> &'/" | sh
_variables
fonction debash_completion
, qui stocke le résultat d'une substitution de commande dans une variable globaleCOMPREPLY
. Si une solution de pipeline était utilisée pour conserver les nouvelles lignes, le résultat serait perdu. Dans votre réponse, on a l'impression que les deux solutions sont également bonnes. De plus, il convient de noter que le comportement de la solution de pipeline dépend fortement du shell: un utilisateur pourrait testerecho foo | { var=$(sed '$s/$/./'); var=${var%.}; } ; echo $var
avec ksh93 et zsh, et pense que c'est OK, alors que ce code est bogué.$var
disparaît" (ce qui n'est pas vrai car cela dépend du shell - le comportement n'est pas spécifié par POSIX), ce qui est une phrase plutôt neutre. La deuxième solution est meilleure car elle ne souffre pas de ce problème et son comportement est cohérent dans tous les shells POSIX.