Je sais que cat
peut le faire, mais son objectif principal est de concaténer plutôt que de simplement afficher le contenu.
Je connais également less
et more
, mais je cherche quelque chose de simple (pas un pager) qui ne fait que sortir le contenu d'un fichier sur le terminal et c'est fait spécialement pour ça, s'il y a une telle chose.
Le plus évident est cat
. Mais jetez également un œil à head
et tail
. Il existe également d'autres utilitaires Shell pour imprimer un fichier ligne par ligne: sed
, awk
, grep
. Mais ceux-ci consistent à alterner le contenu du fichier ou à rechercher à l'intérieur du fichier.
J'ai fait quelques tests pour estimer lequel est le plus efficace. J'exécute tous les creux strace
pour voir lequel a fait le moins d'appels système. Mon fichier contient 1275 lignes.
awk
: 1355 appels systèmecat
: 51 appels systèmegrep
: 1337 appels systèmehead
: 93 appels systèmetail
: 130 appels systèmesed
: 1378 appels systèmeComme vous pouvez le voir, même si cat
a été conçu pour concaténer des fichiers, il est le plus rapide et le plus efficace. sed
, awk
et grep
ont imprimé le fichier ligne par ligne, c'est pourquoi ils ont plus de 1275 appels système.
Je sais que
cat
peut le faire, mais son objectif principal est de concaténer plutôt que de simplement afficher le contenu.
Le but de cat
est exactement cela, lire un fichier et le sortir vers stdout.
Tout d'abord, cat
écrit dans la sortie standard, qui n'est pas nécessairement un terminal, même si cat
a été tapé dans le cadre d'une commande dans un shell interactif. Si vous avez vraiment besoin de quelque chose à écrire sur le terminal même lorsque la sortie standard est redirigée, ce n'est pas si facile (vous devez spécifier quel terminal, et il pourrait même ne pas y en avoir un si la commande est exécutée à partir d'un script), même si un pourrait (ab) utiliser la sortie d'erreur standard si la commande fait simplement partie d'un pipeline. Mais puisque vous avez indiqué que cat
fait le travail, je suppose que vous ne posiez pas de question sur une telle situation.
Si votre objectif était d'envoyer ce qui est écrit dans la sortie standard dans un pipeline, alors l'utilisation de cat
serait éligible au seless Use of Cat Award , puisque cat file | pipeline
(où pipeline
représente n'importe quel pipeline) peut être fait plus efficacement que <file pipeline
. Mais encore une fois, de votre formulation, je déduis que ce n'était pas votre intention.
Il n'est donc pas si clair de quoi vous vous inquiétez. Si vous trouvez cat
trop long pour taper, vous pouvez définir un alias à un ou deux caractères (il y a encore quelques noms de ce type qui restent inutilisés dans Unix standard). Si toutefois vous craignez que cat
passe des cycles inutiles, vous ne devriez pas.
S'il y avait un programme null
qui ne prend aucun argument et copie simplement l'entrée standard sur la sortie standard (l'objet neutre pour les pipelines), vous pourriez faire ce que vous voulez avec <file null
. Il n'y a pas un tel programme, bien qu'il soit facile à écrire (un programme C avec juste une fonction main
sur une ligne peut faire le travail), mais appeler cat
sans arguments (ou cat -
Si vous voulez être explicite) fait exactement cela.
S'il y avait un programme nocat
qui prend exactement un argument de nom de fichier, essaie d'ouvrir le fichier, se plaint s'il ne peut pas, et sinon procède à la copie du fichier vers la sortie standard, alors ce serait exactement ce que vous êtes Demander. Il n'est que légèrement plus difficile à écrire que null
, le travail principal étant d'ouvrir le fichier, de tester et éventuellement de se plaindre (si vous êtes méticuleux, vous voudrez peut-être également inclure un test indiquant qu'il existe exactement un argument, et se plaindre du contraire). Mais là encore, cat
, désormais fourni avec un seul argument, fait exactement cela, donc il n'y a pas besoin de programme nocat
.
Une fois que vous avez réussi à écrire le programme nocat
, pourquoi s'arrêter à un seul argument? Envelopper le code dans une boucle for(;*argp!=NULL;++argp)
ne demande vraiment aucun effort, ajoute tout au plus quelques instructions machine au binaire, et évite d'avoir à se plaindre d'un nombre incorrect d'arguments (ce qui épargne beaucoup plus d'instructions) . Voilà une version primitive de cat
, concaténant des fichiers. (Pour être honnête, vous devez le modifier un peu afin que, sans arguments, il se comporte comme null
.)
Bien sûr, dans le vrai programme cat
, ils ont ajouté quelques cloches et sifflets, car ils le font toujours. Mais l'essentiel est que l'aspect "concaténation" de cat
ne coûte vraiment aucun effort, ni pour le programmeur ni pour la machine qui l'exécute. Le fait que cat
subsume null
et nocat
explique la non-existence de tels programmes. Évitez d'utiliser cat
avec un seul argument si le résultat va dans un pipeline, mais s'il est utilisé uniquement pour afficher le contenu du fichier sur le terminal, même la page que j'ai liée admet qu'il s'agit d'une utilisation utile de cat
, alors n'hésitez pas.
Vous pouvez tester que cat
est vraiment implémenté par une simple boucle autour d'une fonctionnalité nocat
hypothétique, en appelant cat
avec plusieurs noms de fichiers dont un nom invalide, pas dans le premier position: plutôt que de se plaindre immédiatement que ce fichier n'existe pas, cat
vide d'abord les fichiers valides précédents, puis se plaint du fichier invalide (du moins c'est ainsi que se comporte mon chat).
Sous zsh
essayez
<file
Je pense que c'est le moyen le plus court d'imprimer un fichier. Il utilise 'caché' cat
(ou more
si stdout est un terminal), mais la commande utilisée pour l'impression est contrôlée par la variable READNULLCMD
que vous pouvez écraser en toute sécurité directement par commande nom ou même par une fonction. Par exemple, pour imprimer des fichiers avec une numérotation de ligne:
numcat() { nl -s'> ' -w2 - }
READNULLCMD=numcat
<file
Je sais que c'est une question du passé. Techniquement, puisque l'impression du contenu d'un fichier dans stdout
est une forme de concaténation, cat
est sémantiquement appropriée. N'oubliez pas que printf
est sémantiquement destiné à formater et imprimer des données. Bash fournit également une syntaxe pour rediriger l'entrée et la sortie des fichiers. Une combinaison de ces éléments pourrait produire ceci:
printf '%s' "$(<file.txt)"
POSIX définit cat comme:
[~ # ~] nom [~ # ~]
cat - concaténer et imprimer des fichiers
[~ # ~] synopsis [~ # ~]
chat [-u] [fichier ...]
[~ # ~] description [~ # ~]
L'utilitaire cat doit lire les fichiers en séquence et écrire leur contenu sur la sortie standard dans la même séquence.
Je pense donc que concaténer signifie ici lire les fichiers dans l'ordre.
Utilisation de bash
internes et évitant la création de sous-processus:
{ while IFS='' read -rd '' _bcat_; do printf '%s\0' "${_bcat_}"; done; printf '%s' "${_bcat_}"; unset _bcat_; } <'/path/to/file'
IFS
ne sera appliqué qu'à la commande read
, donc ne vous inquiétez pas de vos modifications globales IFS
.
Boucle requise pour gérer les caractères nuls (merci à Stéphane Chazelas).
Cette méthode ne convient pas aux gros fichiers car le contenu du fichier est lu en premier dans la variable (donc la mémoire). BTW J'ai essayé d'imprimer un fichier texte de 39M de cette façon et l'utilisation de la mémoire bash n'a pas dépassé 5M, donc je ne suis pas sûr de ce cas.
Il est également sacrément lent et inefficace sur le processeur: pour le même fichier de 39 millions, cela a pris environ 3 minutes avec une utilisation à 100% d'un seul cœur.
Pour les gros fichiers ou les binaires, mieux utiliser cat '/path/to/file'
ou même dd if='/path/to/file' bs=1M
si possible.
Tout comme une démonstration, vous pouvez faire
cp foo /dev/stdout