Bash: Usunięcie końcowego podziału linii z wyjścia

188

Kiedy wykonuję polecenia w języku Bash (a ściślej wc -l < log.txt), dane wyjściowe zawierają po nim łamanie wierszy. Jak się tego pozbyć?

heksacyjanid
źródło

Odpowiedzi:

250

Jeśli oczekiwanym wyjściem jest pojedynczy wiersz , możesz po prostu usunąć wszystkie znaki nowego wiersza z wyniku. Nie jest niczym niezwykłym podłączanie do narzędzia „tr” lub Perla, jeśli jest to preferowane:

wc -l < log.txt | tr -d '\n'

wc -l < log.txt | perl -pe 'chomp'

Możesz także użyć podstawienia polecenia, aby usunąć końcowy znak nowej linii:

echo -n "$(wc -l < log.txt)"

printf "%s" "$(wc -l < log.txt)"

Należy pamiętać, że nie zgadzam się z decyzją PO o wyborze zaakceptowanej odpowiedzi. Uważam, że w miarę możliwości należy unikać używania „xargs”. Tak, to fajna zabawka. Nie, nie potrzebujesz go tutaj.


Jeśli oczekiwane dane wyjściowe mogą zawierać wiele wierszy , musisz podjąć inną decyzję:

Jeśli chcesz usunąć MULTIPLE znaki nowej linii z końca pliku, ponownie użyj podstawienia cmd:

printf "%s" "$(< log.txt)"

Jeśli chcesz ściśle usunąć OSTATNI znak nowej linii z pliku, użyj Perla:

perl -pe 'chomp if eof' log.txt


Zauważ, że jeśli jesteś pewien, że masz końcowy znak nowej linii, który chcesz usunąć, możesz użyć „head” z GNU coreutils, aby wybrać wszystko oprócz ostatniego bajtu. Powinno to być dość szybkie:

head -c -1 log.txt

Ponadto, dla kompletności, możesz szybko sprawdzić, gdzie znajdują się twoje znaki nowej linii (lub inne znaki specjalne) w twoim pliku, używając „cat” i flagi „pokaż wszystko”. Znak dolara wskazuje koniec każdej linii:

cat -A log.txt
Steve
źródło
To usuwa WSZYSTKIE nowe wiersze z wyniku, a nie tylko końcowy nowy wiersz, jak pyta tytuł.
Cody A. Ray,
@ CodyA.Ray: Musisz jednak zgodzić się, że pytanie opisuje konkretne polecenie, które zawsze wygeneruje tylko jeden wiersz wyniku. Zaktualizowałem jednak moją odpowiedź, aby pasowała do bardziej ogólnego przypadku. HTH.
Steve
3
Byłoby lepiej, gdyby krótkie opcje zostały zastąpione długimi. Długie opcje uczą, a także funkcji, np tr --delete '\n'.
Elijah Lynn,
1
Ja też tak zrobiłem| tr -d '\r'
AlikElzin-kilaka
Warto zauważyć, że rozwiązanie zastępowania cmd może prowadzić do wydłużenia linii, jeśli plik jest bardzo duży.
phk
88

Jednokierunkowa:

wc -l < log.txt | xargs echo -n
Satya
źródło
24
Lepiej:echo -n `wc -l log.txt`
Satya
9
Dlaczego wykonywanie poleceń w backtickach jest lepsze niż używanie potoku?
Matthew Schinckel
2
Spowoduje to nie tylko usunięcie końcowych znaków nowej linii, ale także ściśnięcie kolejnych białych spacji (a dokładniej, jak zdefiniowano IFS) w jednym miejscu. Przykład echo "a b" | xargs echo -n:; echo -n $(echo "a b"). Może to stanowić problem w przypadku użycia.
musiphil
14
Co gorsza, jeśli dane wyjściowe zaczynają się od -e, będą interpretowane jako opcja echo. Jest zawsze bezpieczniejszy w użyciu printf '%s'.
musiphil
1
xargsjest bardzo wolny w moim systemie (i podejrzewam, że dotyczy to również innych systemów), więc printf '%s' $(wc -l log.txt)może być szybszy, ponieważ printfzwykle jest wbudowany (również dlatego, że nie ma przekierowania informacji). Nigdy nie używaj backticków, były one przestarzałe w nowszych wersjach POSIX i mają wiele wad.
rr
14

Istnieje również bezpośrednie wsparcie dla usuwania białych znaków w podstawieniu zmiennych Bash :

testvar=$(wc -l < log.txt)
trailing_space_removed=${testvar%%[[:space:]]}
leading_space_removed=${testvar##[[:space:]]}
Andrey Taranov
źródło
1
Możesz także użyćtrailing_linebreak_removed=${testvar%?}
PairedPrototype
Zauważ, że jeśli używasz podstawiania poleceń, nie musisz nic robić, aby usunąć końcowe znaki nowej linii. Bash już to robi w ramach zastępowania poleceń: gnu.org/software/bash/manual/html_node/…
Michael Burr,
10

Jeśli przypiszesz jego wynik do zmiennej, bashautomatycznie usuwa białe znaki:

linecount=`wc -l < log.txt`
nneonneo
źródło
10
Końcowe znaki nowej linii są dokładnie usuwane. Usuwa je podstawienie polecenia, a nie przypisanie zmiennej.
chepner
2
Widziałem w Cygwin bash końcowe spacje nie usuwane przy użyciu $ (cmd / c echo% VAR%). W tym przypadku musiałem użyć $ {var %% [[: space:]]}.
Andrey Taranov,
1
Uwaga: to nie przypisanie zmiennej, ale rozszerzenie wyrażenia usuwa znaki nowej linii.
Ciro Santilli 26 冠状 病 六四 事件 法轮功
10

printf już przycina dla ciebie końcowy znak nowej linii:

$ printf '%s' $(wc -l < log.txt)

Szczegół:

  • printf wydrukuje twoją treść zamiast %s zastępczego łańcucha znaków.
  • Jeśli nie powiesz mu, aby wypisał znak nowej linii ( %s\n), nie zrobi tego.
zero2cx
źródło
7
Jeśli umieścisz podwójne cudzysłowy wokół polecenia, np "$(command)". Wewnętrzne znaki nowej linii zostaną zachowane - i tylko nowa linia końcowa zostanie usunięta. Powłoka wykonuje tutaj całą pracę - printfjest tylko sposobem na skierowanie wyników podstawiania poleceń z powrotem stdout.
Brent Bradburn,
2
To nie printf usuwa nową linię tutaj, to powłoka robi to z $( )konstrukcją. Oto dowód:printf "%s" "$(perl -e 'print "\n"')"
Flimm
Ponownie warto zauważyć, że wynikowa linia poleceń może stać się zbyt długa.
phk
Jest to wygodne rozwiązanie z sugestią @ nobar:$ printf '%s' "$(wc -l < log.txt)"
Ilias Karim
10

Jeśli chcesz usunąć tylko ostatnią nową linię , przeciągnij przez:

sed -z '$ s/\n$//'

sednie doda \0końca do tego strumienia, jeśli ogranicznik jest ustawiony na NULvia -z, natomiast aby utworzyć plik tekstowy POSIX (zdefiniowany jako koniec a \n), zawsze będzie wyświetlał końcowy \nbez -z.

Na przykład:

$ { echo foo; echo bar; } | sed -z '$ s/\n$//'; echo tender
foo
bartender

I aby udowodnić, że nie NULdodano:

$ { echo foo; echo bar; } | sed -z '$ s/\n$//' | xxd
00000000: 666f 6f0a 6261 72                        foo.bar

Aby usunąć wiele końcowych znaków nowej linii , przeciągnij przez:

sed -Ez '$ s/\n+$//'
Tom Hale
źródło
Podejrzewam, że jest to rozszerzenie GNU, którego Mac sednie zapewnia -z.
Spidey
7

Jeśli chcesz wydrukować wynik czegokolwiek w Bash bez końca linii, echo to -nprzełącznikiem.

Jeśli masz go już w zmiennej, powtórz echo z przyciętym końcowym znakiem nowej linii :

    $ testvar=$(wc -l < log.txt)
    $ echo -n $testvar

Lub możesz to zrobić w jednym wierszu, zamiast tego:

    $ echo -n $(wc -l < log.txt)
Rastislav Hasicek
źródło
2
Zmienna jest technicznie niepotrzebna. echo -n $(wc -l < log.txt)ma ten sam efekt.
chepner