La commande shell suivante était censée imprimer uniquement les lignes impaires du flux d'entrée:
echo -e "aaa\nbbb\nccc\nddd\n" | (while true; do head -n 1; head -n 1 >/dev/null; done)
Mais au lieu il imprime juste la première ligne: aaa
.
La même chose ne se produit pas lorsqu'elle est utilisée avec l' option -c
( --bytes
):
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 >/dev/null; done)
Cette commande sort 1234512345
comme prévu. Mais cela ne fonctionne que dans l' implémentation coreutils de l' head
utilitaire. L' implémentation de busybox mange toujours des caractères supplémentaires, donc la sortie est juste 12345
.
Je suppose que ce mode de mise en œuvre spécifique est effectué à des fins d'optimisation. Vous ne pouvez pas savoir où se termine la ligne, vous ne savez donc pas combien de caractères vous devez lire. La seule façon de ne pas consommer de caractères supplémentaires dans le flux d'entrée est de lire le flux octet par octet. Mais la lecture du flux un octet à la fois peut être lente. Je suppose donc qu'il head
lit le flux d'entrée dans un tampon suffisamment grand, puis compte les lignes dans ce tampon.
On ne peut pas en dire autant du cas où l' --bytes
option est utilisée. Dans ce cas, vous savez combien d'octets vous devez lire. Vous pouvez donc lire exactement ce nombre d'octets et pas plus que cela. L' implémentation de corelibs utilise cette opportunité, mais pas celle de busybox , elle lit toujours plus d'octets que nécessaire dans un tampon. Cela est probablement fait pour simplifier la mise en œuvre.
Donc la question. Est-il correct que l' head
utilitaire consomme plus de caractères du flux d'entrée qu'il ne lui a été demandé? Existe-t-il une sorte de standard pour les utilitaires Unix? Et s'il y en a un, spécifie-t-il ce comportement?
PS
Vous devez appuyer sur Ctrl+C
pour arrêter les commandes ci-dessus. Les utilitaires Unix n'échouent pas à la lecture au-delà EOF
. Si vous ne voulez pas appuyer, vous pouvez utiliser une commande plus complexe:
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 | [ `wc -c` -eq 0 ] && break >/dev/null; done)
que je n'ai pas utilisé pour plus de simplicité.