De nombreux utilitaires de ligne de commande peuvent prendre leur entrée à partir d'un canal ou d'un argument de nom de fichier. Pour les scripts shell longs, je trouve que le démarrage de la chaîne avec la cat
rend plus lisible, en particulier si la première commande a besoin d'arguments sur plusieurs lignes.
Comparer
sed s/bla/blaha/ data \
| grep blah \
| grep -n babla
et
cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla
Cette dernière méthode est-elle moins efficace? Si tel est le cas, la différence est-elle suffisante pour que le script soit exécuté, par exemple une fois par seconde? La différence de lisibilité n'est pas énorme.
shell-script
performance
pipe
cat
Tshepang
la source
la source
cat
. Cependant, je pense que la plus grande question ici est la lisibilité du code, qui est souvent une priorité par rapport aux performances. Quand plus vite peut réellement être écrit plus joli , pourquoi pas? Souligner le problème aveccat
conduit généralement l'utilisateur à une meilleure compréhension des pipelines et des processus en général. Cela en vaut la peine, alors ils écrivent du code compréhensible la prochaine fois.cat
; l'argument de Caleb concernant l'utilisation de fonctions et la redirection résout également ce problème.)Réponses:
La réponse "définitive" vous est bien sûr apportée par The Useless Use of
cat
Award .Instancier chat juste pour que votre code se lit différemment ne nécessite qu'un processus supplémentaire et un ensemble de flux d'entrée / sortie supplémentaire qui ne sont pas nécessaires. Généralement, le blocage réel de vos scripts sera constitué par des boucles inefficaces et un traitement réel. Sur la plupart des systèmes modernes, un ajout
cat
ne va pas nuire à vos performances, mais il existepresquetoujours un autre moyen d'écrire votre code.Comme vous le constatez, la plupart des programmes peuvent accepter un argument pour le fichier d'entrée. Cependant, il existe toujours un shell intégré
<
qui peut être utilisé partout où un flux STDIN est attendu, ce qui vous permet d'économiser un processus en effectuant le travail dans le processus shell en cours d'exécution.Vous pouvez même faire preuve de créativité avec O vous écrivez. Normalement, il serait placé à la fin d'une commande avant de spécifier des redirections de sortie ou des tubes comme celui-ci:
Mais ça ne doit pas forcément être comme ça. Cela peut même venir en premier. Par exemple, votre exemple de code pourrait être écrit comme ceci:
Si la lisibilité du script vous préoccupe et que votre code est suffisamment en désordre pour que l'ajout d'une ligne
cat
facilite le suivi, il existe d'autres moyens de nettoyer votre code. L'une des solutions que j'utilise le plus souvent pour faciliter la compréhension des scripts consiste à diviser les canaux en ensembles logiques et à les enregistrer dans des fonctions. Le code de script devient alors très naturel et toute partie de la tôle est plus facile à déboguer.Vous pouvez ensuite continuer avec
fix_blahs < data | fix_frogs | reorder | format_for_sql
. Une ligne de commande qui se lit comme cela est vraiment facile à suivre et les composants individuels peuvent être facilement mis au point dans leurs fonctions respectives.la source
<file
pourrait venir avant la commande. Cela résout tous mes problèmes!<file
peut arriver n'importe où sur la ligne de commande:<file grep needle
ougrep <file needle
ougrep needle <file
. L'exception concerne les commandes complexes telles que les boucles et les regroupements; la redirection doit venir après la fermeturedone
/}
/)
/ etc. @Caleb Ceci est valable pour tous les shells Bourne / POSIX. Et je ne suis pas d'accord pour dire que c'est moche.$(cat /some/file)
par$(< /some/file)
, ce qui fait la même chose mais évite de générer un processus.$(< /some/file)
portabilité est limitée. Cela fonctionne dans bash, mais pas dans BusyBox ash, par exemple, ni dans FreeBSD sh. Cela ne fonctionne probablement pas au tableau de bord non plus, puisque ces trois derniers obus sont tous des cousins proches.Voici un résumé de certains des inconvénients de:
plus de
$file
. Dans le cas decat
, c'est toujours un problème sauf pourzsh
; dans le cas de la redirection, ce n'est un problème que pourbash
ouksh88
et, pour certains autres shells, uniquement lorsqu'il est interactif (pas dans des scripts).cmd
est intégré, il y a même 2 processus dans certains shellsbash
.cat
est intégré, une commande supplémentaire est également exécutée (et bien sûr chargée et initialisée (ainsi que les bibliothèques auxquelles elle est liée)).cat
et lescmd
processus et constamment remplir et vider la mémoire tampon de tuyau. Même si lecmd
fait de1GB
grandsread()
appels système à un moment, le contrôle devra aller et venir entrecat
etcmd
parce qu'un tuyau ne peut pas contenir plus de quelques kilo - octets de données à la fois.cmd
s (commewc -c
) peuvent faire des optimisations lorsque leur stdin est un fichier normal, ce qu’ils ne peuvent fairecat | cmd
car leur stdin n’est alors qu’un tuyau. Aveccat
un tuyau, cela signifie également qu'ils ne peuvent passeek()
dans le fichier. Pour des commandes telles quetac
outail
, cela fait une énorme différence de performances car cela signifiecat
qu’elles ont besoin de stocker toute l’entrée en mémoire.cat $file
, et même sa version plus correctecat -- "$file"
ne fonctionnera pas correctement pour certains noms de fichiers spécifiques comme-
(ou--help
ou quoi que ce soit à partir de-
si vous oubliez le--
). Si on insiste pour utilisercat
, il devrait probablement utilisercat < "$file" | cmd
plutôt pour la fiabilité.$file
ne peut pas être ouvert en lecture (l'accès est refusé, n'existe pas ...),< "$file" cmd
signalera un message d'erreur cohérent (par le shell) et ne s'exécutera pascmd
, alors qu'ilcat $file | cmd
sera toujours exécutécmd
mais avec son stdin qui ressemble à un fichier vide. Cela signifie également que, dans des domaines tels que< file cmd > file2
,file2
n’est pas compressé s’ilfile
ne peut pas être ouvert.la source
truncate -s10G a; time wc -c < a; time cat a | wc -c; time cat a | cat | wc -c
. Il y a beaucoup de paramètres qui entrent dans l'image. La pénalité de performance peut aller de 0 à 100%. En tout cas, je ne pense pas que la sanction puisse être négative.wc -c
est un cas assez unique, car il a un raccourci. Si vous le faites plutôt,wc -w
il est comparable àgrep
mon exemple (c’est-à-dire très peu de traitement - ce qui est la situation où «<» peut faire la différence).wc -w
sur un fichier fragmenté de 1 Go dans les paramètres régionaux C sous Linux 4.9 amd64), je trouve que l'approche cat prend 23% de temps supplémentaire sur un système multicœur et 5% lorsque les lier à un seul noyau. Affichage de la charge supplémentaire occasionnée par l’accès aux données par plusieurs cœurs. Vous obtiendrez peut-être des résultats différents si vous modifiez la taille du tuyau, utilisez des données différentes, impliquez de véritables E / S, utilisez une implémentation cat qui utilise splice () ... Tout confirmant qu'il y a beaucoup de paramètres entrant dans l'image. et celacat
ne vous aidera en aucun cas .wc -w
c'est une différence d'environ 2% ... 15% de différence si c'est dans un simple grep. Ensuite, bizarrement, si c'est sur un partage de fichiers NFS, il est en fait 20% plus rapide à le lire s'il est envoyé depuiscat
( gist.github.com/rdp/7162414833becbee5919cda855f1cb86 ). Bizarre ...Mettre
<file
en fin de pipeline est moins lisible qu’aucat file
début. L'anglais naturel se lit de gauche à droite.Mettre
<file
le début du pipeline est également moins lisible que cat, je dirais. Un mot est plus lisible qu'un symbole, en particulier un symbole qui semble indiquer le mauvais sens.Utiliser
cat
préserve lecommand | command | command
format.la source
<
une fois rend le code moins lisible, car il détruit la cohérence syntaxique d'un multipipeline.<
ressemblant à ceci:alias load='<'
puis utilisez par exempleload file | sed ...
. Les alias peuvent être utilisés dans les scripts après exécutionshopt -s expand_aliases
.Une autre chose que les autres réponses à cette question ne semblent pas avoir directement abordée est que l'utilisation de cette méthode
cat
n'est pas "inutile" dans le sens où "un processus de chat parasite est généré qui ne produit aucun travail"; c'est inutile en ce sens qu '"un processus de chat est créé qui ne fait que du travail inutile".Dans le cas de ces deux:
le shell démarre un processus sed qui lit un fichier ou un stdin (respectivement) puis effectue un traitement - il lit jusqu'à atteindre une nouvelle ligne, remplace le premier "foo" (le cas échéant) sur cette ligne par "bar", puis affiche cette ligne à stdout et boucles.
Dans le cas de:
La coquille déclenche un processus chat et un processus sed, et connecte la sortie standard du chat à la commande stdin. Le processus cat lit un fichier de plusieurs kilos ou peut-être un mégaoctet dans le fichier, puis l'écrit sur sa sortie standard, où le sed sommand récupère à partir de là, comme dans le deuxième exemple ci-dessus. Pendant que sed traite ce morceau, chat lit un autre morceau et l’écrit sur sa sortie standard pour que sed puisse continuer.
En d'autres termes, le travail supplémentaire que nécessite l'ajout de la
cat
commande ne consiste pas uniquement à générer uncat
processus supplémentaire , mais également à lire et à écrire les octets du fichier deux fois au lieu d'une fois. Maintenant, pratiquement et sur les systèmes modernes, cela ne fait pas une différence énorme - cela peut obliger votre système à faire quelques microsecondes de travail inutile. Toutefois, s’il s’agit d’un script que vous prévoyez de distribuer, éventuellement aux personnes qui l’utilisent sur des machines déjà sous-alimentées, quelques microsecondes peuvent s’additionner au fil de nombreuses itérations.la source
cat
.cat
divisé par le ms sanscat
en pourcentage (par exemple 264 ms / 216 ms = 1,22 = 122% = 22% plus lent aveccat
)