2013-09-08 22 views
5

To file.txt:Bash: różnica między kotem a echo

foo:bar:baz:qux:quux 
one:two:tree:four:five:six:seven 
alpha:beta:gamma:delta:epsilon:zeta:eta:teta:iota:kappa:lambda:mu 
the quick brown fox jumps over the lazy dog 

To co próbowałem w terminalu:

[email protected]:~/Desktop$ cat file.txt 
foo:bar:baz:qux:quux 
one:two:tree:four:five:six:seven 
alpha:beta:gamma:delta:epsilon:zeta:eta:teta:iota:kappa:lambda:mu 
the quick brown fox jumps over the lazy [email protected]:~/Desktop$ cat read.sh 
while read -r line 
do 
    echo $line 
done < file.txt 

[email protected]:~/Desktop$ ./read.sh 
foo:bar:baz:qux:quux 
one:two:tree:four:five:six:seven 
alpha:beta:gamma:delta:epsilon:zeta:eta:teta:iota:kappa:lambda:mu 

Moje pytanie brzmi: dlaczego nie read.sh pokazują ostatnie koniec linii, taki jak cat file.txt?

Odpowiedz

6

Ponieważ nie ma końca wiersza w plik.txt, jeśli:

$ od -c file.txt 
0000000 f o o : b a r : b a z : q u x : 
0000020 q u u x \n o n e : t w o : t r e 
0000040 e : f o u r : f i v e : s i x : 
0000060 s e v e n \n a l p h a : b e t a 
0000100 : g a m m a : d e l t a : e p s 
0000120 i l o n : z e t a : e t a : t e 
0000140 t a : i o t a : k a p p a : l a 
0000160 m b d a : m u \n t h e  q u i c 
0000200 k  b r o w n  f o x  j u m p 
0000220 s  o v e r  t h e  l a z y  
0000240 d o g 

Brak \n na końcu pliku.

z drugiej strony zawsze doda nową linię, gdy pojawi się echo wiadomości, jeśli jej nie ma.

+0

'wc -l' to dobry sposób na potwierdzenie tego. Tak więc jest 'od -ta', aby pokazać, gdzie są obecne znaki nowej linii. – Joe

+1

@Joe wc -l nie jest w porządku, aby to wykryć: pokazuje 3, jeśli nie ma treningu \ n - 'od -c' to dobry sposób na potwierdzenie, czy istnieje \ n - dzięki za napiwek. –

1

Twój plik wejściowy nie kończy się znakiem nowej linii.

po prostu kopiuje zawartość pliku na standardowe wyjście. Działa przez znaki, a nie przez linie, więc nie przejmuje się tym, czy plik kończy się znakiem nowej linii, czy też nie. Ale jeśli nie kończy się na znaku nowej linii, nie doda go do wyjścia.

read -r line odczyta wiersz do zmiennej. Zgłasza tylko sukces, jeśli linia kończy się znakiem nowej linii. Jeśli ostatnia linia danych wejściowych nie kończy się znakiem nowej linii, zgłasza błąd, tak jakby osiągnięto EOF. Tak więc pętla kończy się, gdy próbuje odczytać ostatnią linię, zamiast zwracać tę linię. Dlatego skrypt nigdy nie wyświetla linii zaczynającej się od the quick brown fox.

Ogólnie rzecz biorąc, programy tekstowe w systemie Unix są zdefiniowane tylko do pracy z plikami tekstowymi kończącymi się znakiem nowej linii. Traktowanie ostatniej linii, jeśli nie ma linii nowej, zwykle nie jest określone.

+0

Nigdy nie patrzyłem na zawartość zmiennej, gdy 'read' zwrócił błąd, więc nie zdawałem sobie sprawy z rozróżnienia. Zaktualizowałem swoją odpowiedź. – Barmar

0

Twoja file.txt nie zawiera znaku nowej linii na końcu ostatniej linii. Stąd cat go nie pokazuje.

Zauważ, że read.sh nie wyświetla ostatnią linię w ogóle ... w read.sh, read czeka na kompletną linię wejścia, a od ostatniego wiersza nie jest zakończony znakiem nowej linii, więc nie jest to faktycznie czytać.

4

Inne odpowiedzi są słuszne, po prostu nie ma znaku nowej linii na końcu twojej file.txt.

Większość edytorów tekstu automatycznie kończy plik za pomocą znaku nowej linii, a nawet robi to nano. Ale twój plik został wygenerowany przez skrypt, prawda? Aby odtworzyć to zachowanie wszystko co musisz zrobić, to:

echo -n 'hello world' >> file.txt 

-n flaga mówi nie echo do wyprowadzania znak nowej linii spływu.

Ponadto, jeśli chcesz, aby Twój kod read do pracy, można użyć to:

while read -r line 
do 
    printf "%s\n" "$line" 
done < file.txt 
[[ -n $line ]] && printf '%s' "$line" 

To będzie działać, ponieważ faktycznie read umieści ostatni wiersz w zmiennej, ale także powróci false, co powoduje przerwanie pętli while.