Le script Perl ( my.pl
) suivant peut lire à partir du fichier sur la ligne de commande args ou de STDIN:
while (<>) {
print($_);
}
perl my.pl
lira à partir de STDIN, tandis que perl my.pl a.txt
lira à partir de a.txt
. C'est très pratique.
Vous vous demandez s'il y a un équivalent dans Bash?
/proc/$$/fd/0
et/dev/stdin
? J'ai remarqué que ce dernier semble être plus courant et semble plus simple.-r
à votreread
commande, afin qu'elle ne mange pas accidentellement des\
caractères; utiliserwhile IFS= read -r line
pour conserver les espaces de début et de fin./bin/sh
- utilisez -vous un shell autre quebash
oush
?La solution la plus simple est peut-être de rediriger stdin avec un opérateur de redirection fusionné:
Stdin est le descripteur de fichier zéro. Ce qui précède envoie l'entrée redirigée vers votre script bash dans moins de stdin.
En savoir plus sur la redirection des descripteurs de fichiers .
la source
<&0
dans cette situation - votre exemple fonctionnera de la même manière avec ou sans lui - apparemment, les outils que vous invoquez à partir d'un script bash par défaut voient le même stdin que le script lui-même (sauf si le script le consomme en premier).Voici le moyen le plus simple:
Usage:
Pour affecter stdin à la variable, vous pouvez utiliser:
STDIN=$(cat -)
ou tout simplementSTDIN=$(cat)
car l'opérateur n'est pas nécessaire (selon le commentaire @ mklement0 ).Pour analyser chaque ligne à partir de l' entrée standard , essayez le script suivant:
Pour lire à partir du fichier ou de stdin (si aucun argument n'est présent), vous pouvez l'étendre à:
Voir: Comment lire stdin quand aucun argument n'est passé? à stackoverflow SE
la source
[ "$1" ] && FILE=$1 || FILE="-"
àFILE=${1:--}
. (Quibble: mieux pour éviter les variables de shell tout en majuscules pour éviter les collisions de noms avec les variables d' environnement .)${1:--}
est compatible POSIX, donc il devrait fonctionner dans tous les shells de type POSIX. Ce qui ne fonctionnera pas dans tous ces shells, c'est la substitution de processus (<(...)
); cela fonctionnera en bash, ksh, zsh, mais pas en dash, par exemple. Aussi, mieux vaut ajouter-r
à votreread
commande, afin qu'elle ne mange pas accidentellement des\
caractères; ajouterIFS=
au début pour conserver les espaces de début et de fin.echo
: si une ligne se compose de-e
,-n
ou-E
, elle ne sera pas affichée. Pour résoudre ce problème, vous devez utiliserprintf
:printf '%s\n' "$line"
. Je ne l'ai pas inclus dans ma précédente édition… trop souvent mes modifications sont annulées lorsque je corrige cette erreur:(
.--
est inutile si le premier argument est'%s\n'
IFS=
avecread
etprintf
au lieu deecho
.:)
.Je pense que c'est la voie directe:
-
-
la source
read
lit à partir de stdin par défaut , donc il n'y a pas besoin de< /dev/stdin
.La
echo
solution ajoute de nouvelles lignes chaque fois queIFS
le flux d'entrée est interrompu. La réponse de @ fgm peut être modifiée un peu:la source
read
comportement de ': whileread
est potentiellement divisé en plusieurs jetons par les caractères. contenu dans$IFS
, il ne renvoie qu'un seul jeton si vous ne spécifiez qu'un seul nom de variable (mais les trims et les espaces de début et de fin par défaut).read
et$IFS
-echo
lui - même ajoute de nouvelles lignes sans le-n
drapeau. "L'utilitaire d'écho écrit tous les opérandes spécifiés, séparés par des caractères blancs ('') et suivis d'un caractère de nouvelle ligne (\ \ ') dans la sortie standard."\n
ajoutée parecho
: Perl$_
inclut la ligne se terminant à\n
partir de la ligne lue,read
contrairement à bash . (Cependant, comme @gniourf_gniourf le fait remarquer ailleurs, l'approche la plus robuste consiste à utiliserprintf '%s\n'
à la place deecho
).La boucle Perl dans la question lit à partir de tous les arguments de nom de fichier sur la ligne de commande, ou à partir de l'entrée standard si aucun fichier n'est spécifié. Les réponses que je vois semblent toutes traiter un seul fichier ou une entrée standard si aucun fichier n'est spécifié.
Bien que souvent ridiculisé avec précision comme UUOC (utilisation inutile de
cat
), il y a des moments oùcat
est le meilleur outil pour le travail, et on peut soutenir que c'est l'un d'entre eux:Le seul inconvénient est qu'il crée un pipeline s'exécutant dans un sous-shell, donc des choses comme les affectations de variables dans la
while
boucle ne sont pas accessibles en dehors du pipeline. Labash
solution est la substitution de processus :Cela laisse la
while
boucle en cours d'exécution dans le shell principal, donc les variables définies dans la boucle sont accessibles en dehors de la boucle.la source
>>EOF\n$(cat "$@")\nEOF
. Enfin, un petit problème:while IFS= read -r line
est une meilleure approximation de ce qui sewhile (<>)
passe en Perl (préserve les espaces de début et de fin - bien que Perl conserve également le dernier\n
).Le comportement de Perl, avec le code donné dans l'OP, peut prendre aucun ou plusieurs arguments, et si un argument est un trait d'union,
-
cela est compris comme stdin. De plus, il est toujours possible d'avoir le nom de fichier avec$ARGV
. Aucune des réponses données jusqu'à présent ne reproduit vraiment le comportement de Perl à cet égard. Voici une pure possibilité Bash. L'astuce consiste à utiliser deexec
manière appropriée.Le nom de fichier est disponible en
$1
.Si aucun argument n'est donné, nous le définissons artificiellement
-
comme premier paramètre positionnel. On boucle ensuite sur les paramètres. Si un paramètre ne l'est pas-
, nous redirigeons l'entrée standard du nom de fichier avecexec
. Si cette redirection réussit, nous bouclons avec unewhile
boucle. J'utilise laREPLY
variable standard , et dans ce cas, vous n'avez pas besoin de réinitialiserIFS
. Si vous voulez un autre nom, vous devez le réinitialiserIFS
comme ça (à moins, bien sûr, que vous ne le vouliez pas et que vous sachiez ce que vous faites):la source
Plus précisément...
la source
IFS=
et-r
à laread
commande garantit que chaque ligne est lue sans modification (y compris les espaces de début et de fin).Veuillez essayer le code suivant:
la source
read
sansIFS=
et-r
, et le pauvre$line
sans ses citations saines.read -r
notation. IMO, POSIX s'est trompé; L'option doit activer la signification spéciale pour les barres obliques inverses de fin, et non la désactiver - afin que les scripts existants (antérieurs à POSIX) ne se cassent pas car le a-r
été omis. J'observe, cependant, qu'il faisait partie de l'IEEE 1003.2 1992, qui était la première version de la norme shell et utilitaires POSIX, mais il a été marqué comme un ajout même à ce moment-là, ce qui fait chier des opportunités de longue date. Je n'ai jamais rencontré de problèmes car mon code n'utilise pas-r
; Je dois avoir de la chance. Ignorez-moi à ce sujet.-r
devrait être standard. Je suis d'accord qu'il est peu probable que ce soit dans les cas où ne pas l'utiliser entraîne des problèmes. Cependant, un code cassé est un code cassé. Mon montage a d'abord été déclenché par cette pauvre$line
variable qui manquait beaucoup ses citations. J'ai corrigé leread
temps que j'y étais. Je n'ai pas corrigé le problèmeecho
car c'est le type de modification qui est annulé.:(
.Le code
${1:-/dev/stdin}
comprendra simplement le premier argument, alors, qu'en est-il.la source
Je ne trouve aucune de ces réponses acceptable. En particulier, la réponse acceptée ne gère que le premier paramètre de ligne de commande et ignore le reste. Le programme Perl qu'il essaie d'émuler gère tous les paramètres de ligne de commande. La réponse acceptée ne répond donc même pas à la question. D'autres réponses utilisent des extensions bash, ajoutent des commandes «cat» inutiles, ne fonctionnent que pour le cas simple d'écho d'entrée en sortie, ou sont simplement inutilement compliquées.
Cependant, je dois leur donner un certain crédit car ils m'ont donné quelques idées. Voici la réponse complète:
la source
J'ai combiné toutes les réponses ci-dessus et créé une fonction shell qui conviendrait à mes besoins. C'est à partir d'un terminal cygwin de mes 2 machines Windows10 où j'avais un dossier partagé entre eux. Je dois être capable de gérer les éléments suivants:
cat file.cpp | tx
tx < file.cpp
tx file.cpp
Lorsqu'un nom de fichier spécifique est spécifié, je dois utiliser le même nom de fichier lors de la copie. Lorsque le flux de données d'entrée a été acheminé, j'ai besoin de générer un nom de fichier temporaire contenant les heures, les minutes et les secondes. Le dossier principal partagé a des sous-dossiers des jours de la semaine. C'est à des fins d'organisation.
Voici, le script ultime pour mes besoins:
S'il y a un moyen que vous pouvez voir pour optimiser davantage cela, je voudrais le savoir.
la source
Ce qui suit fonctionne en standard
sh
(testé avecdash
sur Debian) et est assez lisible, mais c'est une question de goût:Détails: Si le premier paramètre n'est pas vide, alors
cat
ce fichier, sinoncat
entrée standard. Ensuite, la sortie de l'if
instruction entière est traitée par lecommands_and_transformations
.la source
cat "${1:--}" | any_command
. La lecture des variables shell et leur écho peuvent fonctionner pour les petits fichiers mais ne sont pas aussi bien mis à l'échelle.[ -n "$1" ]
peut être simplifié en[ "$1" ]
.Celui-ci est facile à utiliser sur le terminal:
la source
Que diriez-vous
la source
cat
sera placée dans la ligne de commande. La ligne de commande a une taille maximale. De plus, cela ne lira pas ligne par ligne, mais mot par mot.