Dlaczego bash usuwa \ n w $ (plik cat)?

24

Jeśli mam plik input.txtzawierający:

hello
world
!

Następnie wykonanie polecenia bash echo $(cat input.txt)wyświetli to:

hello world !

Dlaczego i jak mogę to naprawić, aby wyświetlało dokładnie to, co jest w pliku, jak jest w pliku?

f. kardynał
źródło

Odpowiedzi:

32

Jeśli użyjesz

echo "$(cat input.txt)"

będzie działać poprawnie.

Prawdopodobnie dane wejściowe echa są oddzielone znakami nowej linii i będzie to obsługiwać jako osobne polecenia, więc wynik będzie bez znaków nowej linii.

ariański
źródło
Miły! Jaka jest różnica (jeśli występuje) pomiędzy $ () a backticks? (Przepraszam, jeśli jest to zbyt styczne)
Chan-Ho Suh,
Są równoważne, z wyjątkiem faktu, że $ (...) jest łatwiejsze do zagnieżdżenia. W obu przypadkach, jeśli nie podasz wyniku, zostanie on podzielony na wiele argumentów na białym spacji.
James Henstridge
3
Ale ostatni znak nowej linii jest pomijany, nawet w podwójnych cudzysłowach. W przeciwieństwie do tego operator ruchu wstecznego Perla rozszerza się na cały wynik polecenia, łącznie ze wszystkimi znakami nowej linii.
Keith Thompson
6
@KeithThompson tak, podstawienie polecenia usuwa wszystkie końcowe znaki nowej linii z wyniku. Ma to tę zaletę, że np. echo "$(date) something"Usuwa końcowy znak nowej linii z wyjścia date, dzięki czemu echo wypisuje datę i „coś” w tym samym wierszu. Jeśli chcesz zapisać plik lub dane wyjściowe polecenia „tak jak jest”, użyj mapfile ( help mapfile) read -rd ''lub pętli odczytu while.
geirha
Dzięki wszystkim :-) Nauczyłem się czegoś z każdego komentarza tutaj!
Chan-Ho Suh
2

Cytat ze strony podręcznika bash, sekcja Command Substitution:

Osadzone znaki nowej linii nie są usuwane, ale mogą zostać usunięte podczas dzielenia słów.

Nieco dalej, ta sama sekcja:

Jeśli podstawienie pojawia się w podwójnych cudzysłowach, dzielenie słów i rozwijanie nazw ścieżek nie są wykonywane w wynikach.

Właśnie dlatego echo "$(cat /etc/passwd)" działa.

Ponadto należy pamiętać, że podstawienie polecenia według specyfikacji POSIX usuwa końcowe znaki nowego wiersza:

$ echo "$(printf "one\ntwo\n\n\n")"
one
two

W związku z tym wysyłanie pliku przez $(cat file.txt)może prowadzić do utraty końcowych znaków nowego wiersza, co może stanowić problem, jeśli integralność całego pliku ma priorytet.

Sergiy Kolodyazhnyy
źródło
2

Możesz zachować nowe wiersze, na przykład ustawiając IFS na pusty:

$ IFS=
$ a=$(cat links.txt)
$ echo "$a"
link1
link2
link3
Sarnath Jegadeesan
źródło