2017-08-13 3 views
0

Bash Version 4.4.7.Seltsames Ergebnis beim Lesen der "ersten und letzten Zeile" von der Katzenausgabe mit "Kopf" und "Schwanz"

Von tutorial, die ersten und die letzten Zeilen einer Datei zu erhalten:

cat txt_file | (head -n1 && tail -n1) 

aber für große Datei (ich weiß nicht, wie groß das wird funktionieren, aber mit über tausend Zeilen-Datei) dieser Befehl läuft gut, aber für kleine Datei, Beispiel:

11111111 
22222222 
33333333 
44444444 

die Ausgabe des Befehls über nur die erste Zeile ist:

11111111 

Der andere Befehl, awk verwenden, arbeitet mit den beiden Dateien:

awk 'NR==1; END{print}' 
+2

Es scheint mir überhaupt kein merkwürdiges Ergebnis zu sein ... es ist unwahrscheinlich, dass ein 'head && tail' funktioniert, wenn die Eingabe nicht größer als die Puffergröße ist. – donkopotamus

+0

@donkopotamus Ich weiß das nicht, könnten Sie es erklären? Und wie lässt sich Kopf, Schwanz für dieses Beispiel arbeiten! Vielen Dank! – duqu

+0

Können Sie erklären, wie das funktioniert? Jeder Befehl lädt einen Puffer nach dem anderen, versucht, mit diesem Puffer zu beenden und übergibt dann die verbleibenden Puffer an den nächsten Befehl? Wie groß ist normalerweise die Puffergröße oder wie finde ich das heraus? – rubystallion

Antwort

3

Ihre „Frage“ im Moment eigentlich nicht als Frage aufgeworfen, seine nur eine Beobachtung. Um deine Beobachtung jedoch zu erklären. Betrachten Sie den Unterschied zwischen dem Ausgang von:

$ seq 10 | (head -1 && tail -1) 
1 

und

$ seq 1000 | (head -1 && tail -1) 
1 
1000 

Was hier geschieht? Unsere Pipeline arbeitet wie folgt:

  • Sendeleitungen (in diesem Fall mit Zahlen, aber sein nicht anders zu Ihrem cat Beispiel) nach stdout;
  • Lesen stdout wir haben:

    • erste, ein head ... es wird die erste Zeile gedruckt werden und dann am Ende;
    • nächste, eine tail ... es wird beginnen nach der Kopf hat laufen und drucken Sie die letzte Zeile.

jedoch standardmäßig head ist nicht die Datei Zeile für Zeile zu lesen oder sogar Zeichen für Zeichen, bis es einen Zeilenumbruch findet, statt dessen die Datei in Blöcken (eine gepufferte Lese) Lesen . Dieser Chunk könnte zum Beispiel 2048 Bytes sein.

Also unsere Pipeline ist wirklich:

  • Sendeleitungen (in diesem Fall mit Zahlen, aber sein nicht anders zu Ihrem cat Beispiel) nach stdout;
  • Lesen stdout wir haben:

    • erste, ein head ... es wird die erste 2kb von stdin lesen, die erste Zeile gedruckt werden und dann am Ende;
    • nächste, eine tail ... es wird den Rest der Daten nach diesem ersten 2k lesen, weil es nie sieht.

Wenn Ihr Ziel nur ist, um die Ausgabe des ersten Befehls zu erzeugen (Ihre cat) einmal, dann könnten Sie tee, so etwas wie dies vielleicht:

$ seq 10 | tee >(tail -1) | head -2 

auch, dass auf beachten linux, könnten Sie die Pufferung des ersten Befehls, so etwas wie ändern:

$ stdbuf -oL seq 10 | (head -1 && tail -1) 

aber das wird nicht funktionieren, wenn Ihr Befehl fummelt mit seinem Strom (siehe stdbuf)

1

Versuch zu folgenden: sed Lösung:

sed -n '1p;$p' <(seq 1000) 

perl Lösung:

seq 100 | perl -ne 'print if 1..1 or eof' 

bash Lösung mit nur Schwanz:

seq 100 | { IFS= read -r line; echo "$line"; tail -1; } 
Verwandte Themen