Jak usunąć początkowe i końcowe białe znaki z każdego wiersza jakiegoś wyniku?

Chciałbym usunąć wszystkie początkowe i końcowe spacje oraz tabulatory z każdego wiersza w wyniku.

Czy istnieje takie proste narzędzie, jak trim Mogę potokować swoje wyjście?

Przykładowy plik:

test space at back test space at front TAB at end TAB at front sequence of some space in the middle some empty lines with differing TABS and spaces: test space at both ends 

Komentarze

  • Dla każdego, kto szuka tutaj rozwiązania do usuwania znaków nowej linii, to jest inny problem. Z definicji nowa linia tworzy nową linię tekstu. Dlatego wiersz tekstu nie może zawierać nowej linii. Pytanie, które chcesz zadać, brzmi: jak usunąć nową linię z początku lub końca ciągu: stackoverflow.com/questions/369758 lub jak usunąć puste miejsce linie lub wiersze, które są po prostu białymi znakami: serverfault.com/questions/252921

Odpowiedź

awk "{$1=$1;print}" 

lub krócej:

awk "{$1=$1};1" 

Obetnie początkowy i końcowe spacje lub znaki tabulacji 1 a także ściśnij sekwencje tabulatorów i spacje w jedną spację.

To działa, ponieważ kiedy przypiszesz coś do jednego z pól , awk odbudowuje cały rekord (wydrukowane przez print), łącząc wszystkie pola ($1, …, $NF) z OFS (domyślnie spacja).

1 (i prawdopodobnie inny pusty znak zależnie od ustawień regionalnych i awk implementacji)

Komentarze

  • Średnik na drugi przykład jest zbędny. Można użyć: awk '{$1=$1}1'
  • @Brian, nie, ; jest wymagany w standardowej składni awk
  • Interesujące … Żaden średnik nie jest obsługiwany przez gawk, mawk i OS X ' s awk. (Przynajmniej dla moich wersji (odpowiednio 1.2, 4.1.1 i 20070501)
  • Jedyne, co mi się ' nie podoba, to to, że stracić powtarzające się spacje w wierszu. Na przykład echo -e 'foo \t bar' | awk '{$1=$1};1'
  • echo ' hello ' | xargs

Odpowiedź

Polecenie można skondensować w ten sposób, jeśli „używasz GNU sed:

$ sed "s/^[ \t]*//;s/[ \t]*$//" < file 

Przykład

Oto powyższe polecenie w akcji.

$ echo -e " \t blahblah \t " | sed "s/^[ \t]*//;s/[ \t]*$//" blahblah 

Możesz użyć hexdump, aby potwierdzić, że polecenie sed usuwa wybrane znaki poprawnie.

$ echo -e " \t blahblah \t " | sed "s/^[ \t]*//;s/[ \t]*$//" | hexdump -C 00000000 62 6c 61 68 62 6c 61 68 0a |blahblah.| 00000009 

Klasy znaków

Możesz także użyć nazw klas znaków zamiast dosłownie wymieniać takie zestawy, [ \t]:

$ sed "s/^[[:blank:]]*//;s/[[:blank:]]*$//" < file 

Przykład

$ echo -e " \t blahblah \t " | sed "s/^[[:blank:]]*//;s/[[:blank:]]*$//" 

Większość narzędzi GNU, które używają zwykłych wyrażeń ssions (regex) obsługują te klasy (tutaj z ich odpowiednikami w typowych ustawieniach regionalnych C systemu opartego na ASCII (i tam tylko)).

 [[:alnum:]] - [A-Za-z0-9] Alphanumeric characters [[:alpha:]] - [A-Za-z] Alphabetic characters [[:blank:]] - [ \t] Space or tab characters only [[:cntrl:]] - [\x00-\x1F\x7F] Control characters [[:digit:]] - [0-9] Numeric characters [[:graph:]] - [!-~] Printable and visible characters [[:lower:]] - [a-z] Lower-case alphabetic characters [[:print:]] - [ -~] Printable (non-Control) characters [[:punct:]] - [!-/:-@[-`{-~] Punctuation characters [[:space:]] - [ \t\v\f\n\r] All whitespace chars [[:upper:]] - [A-Z] Upper-case alphabetic characters [[:xdigit:]] - [0-9a-fA-F] Hexadecimal digit characters 

Używanie te zamiast dosłownych zestawów zawsze wydają się marnowaniem miejsca, ale jeśli obawiasz się, że Twój kod jest przenośny lub musisz radzić sobie z alternatywnymi zestawami znaków (myślę, że międzynarodowy), wtedy prawdopodobnie będziesz chciał użyć zamiast tego nazw klas .

Odnośniki

Komentarze

  • Zwróć uwagę, że [[:space:]] nie jest odpowiednikiem [ \t] w przypadek ogólny (Unicode itp.). [[:space:]] będzie prawdopodobnie znacznie wolniejsze (ponieważ w Unicode jest o wiele więcej rodzajów białych znaków niż tylko ' ' i '\t'). To samo dotyczy wszystkich innych.
  • sed 's/^[ \t]*//' nie jest przenośny. Właściwie POSIX wymaga nawet tego, aby usunąć sekwencję spacji, ukośnika odwrotnego lub t znaków, a ' jest tym, co GNU sed działa również wtedy, gdy POSIXLY_CORRECT znajduje się w środowisku.
  • Co zrobić, jeśli chcę przyciąć znaki nowej linii? ' \ n \ n text \ n \ n '
  • Podoba mi się rozwiązanie seda z powodu braku inne skutki uboczne, jak w rozwiązaniu awk. Pierwsza odmiana nie działa, gdy wypróbowałem ją teraz w bashu na OSX jsut, ale wersja klasy postaci działa: sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
  • @EugeneBiryukov zobacz mój komentarz na oryginalny post

Odpowiedź

xargs bez argumentów to robią.

Przykład:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

Komentarze

  • Zwraca to również wiele spacji w wiersz, który nie był wymagany w pytaniu
  • @roaima – prawda, ale zaakceptowana odpowiedź również ściska spacje (co nie było wymagane w pytaniu). Myślę, że prawdziwy problem polega na tym, że xargs nie zostanie dostarczony, jeśli dane wejściowe zawierają ukośniki odwrotne i pojedyncze cudzysłowy.
  • @don_crissti, który nie ' nie oznacza jednak, że zaakceptowana odpowiedź poprawnie odpowiada na zadane pytanie. Ale w tym przypadku nie zostało to ' oznaczone jako zastrzeżenie, podczas gdy w zaakceptowanej odpowiedzi tak było. Mam nadzieję, że ' zwróciłem uwagę na fakt, że ' będzie miał znaczenie dla przyszłego czytelnika.
  • To także przerwy w apostrofach, cudzysłowach, znakach ukośnika odwrotnego. Uruchamia również jedno lub więcej wywołań echo. Niektóre implementacje echa przetwarzają również opcje i / lub ukośniki odwrotne … Działa to również tylko w przypadku wejścia jednowierszowego.

Odpowiedź

Zgodnie z sugestią Stéphane Chazelas w zaakceptowanej odpowiedzi możesz teraz
utworzyć skrypt /usr/local/bin/trim:

#!/bin/bash awk "{$1=$1};1" 

i nadaj temu plikowi prawa do wykonywania:

chmod +x /usr/local/bin/trim 

Teraz możesz przekazać każde wyjście do trim, na przykład:

cat file | trim 

(w przypadku poniższych komentarzy: użyłem tego wcześniej: while read i; do echo "$i"; done
, które również działa dobrze, ale jest mniej wydajne)

Komentarze

  • Powodzenia, jeśli plik jest duży i / lub zawiera ukośniki odwrotne.
  • @don_crissti: czy mógłbyś skomentować trochę więcej ?, które rozwiązanie lepiej pasować do dużych plików i jak mogę zmodyfikować moje rozwiązanie, jeśli plik zawiera ukośniki odwrotne?
  • ' Będziesz musiał użyć while read -r line, aby zachować odwrotne ukośniki i nawet wtedy … . Jeśli chodzi o duże pliki / szybkość, tak naprawdę wybrałeś najgorsze rozwiązanie. Nie ' nie sądzę, aby ' było coś gorszego. Zobacz odpowiedzi na Dlaczego używanie pętli powłoki do przetwarzania tekstu jest złe w praktyce? , w tym mój komentarz do ostatniej odpowiedzi, gdzie dodałem łącze do testu porównawczego szybkości. Odpowiedzi sed są w porządku IMO i znacznie lepsze niż read.
  • Możesz także dodać alias w / etc / profile (lub twój ~ / .bashrc lub ~ / .zshrc etc …) alias trim = ” awk ' { \ $ 1 = \ $ 1}; 1 ' ”
  • Nie ma potrzeby stosowania bash, możesz to zrobić #! /usr/bin/awk -f {$1=$1};1. (uważaj na nazwy plików zawierające = znaków)

Odpowiedź

Jeśli przechowujesz wiersze jako zmienne, możesz użyć basha, aby wykonać zadanie:

usuń wiodące białe znaki z ciągu:

shopt -s extglob echo ${text##+([[:space:]])} 

usuń końcowe białe znaki z ciągu:

shopt -s extglob echo ${text%%+([[:space:]])} 

usuń wszystkie białe znaki z ciągu:

echo ${text//[[:space:]]} 

Komentarze

  • Usunięcie wszystkich odstępów z ciągu nie jest tym samym, co usunięcie zarówno początkowych, jak i końcowych spacji (jak w pytaniu).
  • Zdecydowanie najlepsze rozwiązanie – wymaga tylko wbudowanych funkcji bash i żadnych zewnętrznych widełek procesowych.
  • Świetnie. Skrypty działają DUŻO szybciej, jeśli ' nie muszą ściągać zewnętrznych programów (takich jak awk lub sed). Działa to również z ” modern ” (93u +) wersjami ksh.

Odpowiedź

sed -e "s/^[[:space:]]*//" -e "s/[[:space:]]*$//" 

Jeśli czytasz wiersz ze zmiennej powłoki, read robi to już , chyba że otrzymano inne instrukcje .

Komentarze

  • +1 dla read. Jeśli więc podczas czytania przelecisz potokiem do: cat file | while read i; do echo $i; done
  • @rubo z wyjątkiem tego w Twoim przykładzie zmienna niecytowana jest również przetwarzana ponownie przez powłokę. Użyj echo "$i", aby zobaczyć prawdziwy efekt read

Odpowiedź

Aby usunąć wszystkie początkowe i końcowe spacje z danego wiersza dzięki narzędziu „potokowemu”, mogę zidentyfikować 3 różne sposoby, które nie są całkowicie równoważne. Różnice te dotyczą odstępów między słowami wiersza wejściowego. W zależności od oczekiwanego b ehaviour, dokonasz wyboru.

Przykłady

Aby wyjaśnić różnice, rozważmy tę fikcyjną linię wejściową:

" \t A \tB\tC \t " 

tr

$ echo -e " \t A \tB\tC \t " | tr -d "[:blank:]" ABC 

tr to naprawdę proste polecenie. W tym przypadku usuwa spację lub znak tabulacji.

awk

$ echo -e " \t A \tB\tC \t " | awk "{$1=$1};1" A B C 

awk usuwa spacje początkowe i końcowe oraz ściska do pojedynczej spacji każdą spację między wyrazami.

sed

$ echo -e " \t A \tB\tC \t " | sed "s/^[ \t]*//;s/[ \t]*$//" A B C 

W tym przypadku sed usuwa spacje początkowe i końcowe bez dotykania spacji między słowami.

Uwaga:

W przypadku jednego słowa w wierszu, tr wykonuje swoje zadanie.

Komentarze

  • Jednak żadna z tych operacji nie ogranicza końcowych / początkowych znaków nowej linii
  • +1 dla listy rozwiązań z ich (czasem nieoczekiwanymi) danymi wyjściowymi.
  • @ user61382 to dość późno, ale zobacz mój komentarz do oryginalnego posta.
  • @highmaintenance: użyj [:space:] zamiast [: blank:], dla polecenia tr, na przykład: ... | tr -d [:space:], aby usunąć również znaki nowej linii. (patrz: man tr)

Odpowiedź

sed to świetne narzędzie do tego:

 # substitute ("s/") sed "s/^[[:blank:]]*//; # parts of lines that start ("^") with a space/tab s/[[:blank:]]*$//" # or end ("$") with a space/tab # with nothing (/) 

Możesz go użyć w tekście, np.

<file sed -e "s/^[[... 

lub działając na nim „inline”, jeśli twój sed jest zgodny z GNU:

sed -i "s/..." file 

ale zmiana źródła w ten sposób jest „niebezpieczna”, ponieważ może być nieodwracalna, gdy nie działa prawidłowo (lub nawet jeśli działa!), więc najpierw wykonaj kopię zapasową (lub użyj -i.bak który ma również tę zaletę, że można go przenosić na niektóre sed s) BSD!

Odpowiedź

Odpowiedź, którą możesz zrozumieć w mgnieniu oka:

#!/usr/bin/env python3 import sys for line in sys.stdin: print(line.strip()) 

Bonus: zastąp str.strip([chars]) z dowolnymi znakami, aby przyciąć lub użyć .lstrip() lub .rstrip() stosownie do potrzeb.

Podobnie jak rubo77 „sa nswer , zapisz jako skrypt /usr/local/bin/trim i nadaj uprawnienia za pomocą chmod +x.

Odpowiedź

Jeśli ciąg, który próbujemy przyciąć, jest krótki i ciągły / ciągły, można go po prostu przekazać jako parametr do dowolnej funkcji bash:

 trim(){ echo $@ } a=" some random string " echo ">>`trim $a`<<" Output >>some random string<< 

Odpowiedź

Napisałem tę funkcję powłoki używając awk

awkcliptor(){ awk -e "BEGIN{ RS="^$" } {gsub(/^[\n\t ]*|[\n\t ]*$/,"");print ;exit}" "$1" ; } 

BEGIN{ RS="^$" }:
na początku przed rozpoczęciem analizowania ustaw rekord
separator na brak tzn. traktuj całe wejście jako
pojedynczy rekord

gsub(this,that):
zastąp to wyrażenie regularne tym ciągiem

/^[\n\t ]*|[\n\t ]*$/:
tego ciągu przechwytuje dowolną spację przed nową linią i klasę tabulacji
lub publikuje spację nowej linii i klasę tabulacji i zastępuje je
pustym ciągiem

print;exit: następnie wydrukuj i zakończ

"$1":
i przekaż pierwszy argument funkcji do be
proces autorstwa awk

jak używać:
skopiuj powyższy kod, wklej w powłoce, a następnie wprowadź
, aby zdefiniować funkcji.
możesz użyć awkcliptor jako polecenia z pierwszym argumentem jako plikiem wejściowym

przykładowe użycie:

echo " ggggg " > a_file awkcliptor a_file 

wyjście:

ggggg 

lub

echo -e "\n ggggg \n\n "|awkcliptor 

wyjście:

ggggg 

Komentarze

  • Czy możesz wyjaśnić różnicę między awk '{$1=$1};1'?

Odpowiedź

Dla tych z nas, którzy nie mają wystarczająco dużo miejsca w mózgu, aby zapamiętać niejasną składnię seda, po prostu odwróć ciąg , przetnij pierwsze pole ogranicznikiem spacji i odwróć je ponownie.

cat file | rev | cut -d" " -f1 | rev 

Komentarze

  • Działa to tylko wtedy, gdy nie ma więcej niż jednej spacji na początku każdego wiersza i nie więcej niż jednego słowa w żadnym wierszu.

Odpowiedź

trimpy () { python3 -c "import sys for line in sys.stdin: print(line.strip())" } trimsed () { gsed -e "s/^[[:space:]]*//" -e "s/[[:space:]]*$//" } trimzsh () { local out="$(</dev/stdin)" [[ "$out" =~ "^\s*(.*\S)\s*$" ]] && out="$match[1]" || out="" print -nr -- "$out" } # example usage echo " hi " | trimpy 

Dodatek: zastąp str.strip([chars]) dowolnymi znakami, aby przyciąć lub użyć lub .rstrip() w razie potrzeby.

Odpowiedź

polecenie translate zadziała

cat file | tr -d [:blank:] 

Komentarze

  • To polecenie nie jest poprawne, ponieważ usuwa wszystkie spacje z pliku, a nie tylko początkowe / końcowe spacje.
  • @BrianRedbeard Masz rację. Jest to nadal przydatna odpowiedź na monolityczny ciąg bez spacji.

Odpowiedź

na przykład bash:

alias trim="awk "{\$1=\$1};1"" 

użycie:

echo -e " hello\t\tkitty " | trim | hexdump -C 

wynik:

00000000 68 65 6c 6c 6f 20 6b 69 74 74 79 0a |hello kitty.| 0000000c 

Komentarze

  • awk '{$1=$1};1' odpowiedź została udzielona dawno temu. Pomysł zrobienia z niego aliasu został zasugerowany w komentarzu prawie tak dawno temu. Tak, możesz wziąć czyjś komentarz i zamienić go w odpowiedź. Ale jeśli to zrobisz, powinieneś przyznać uznanie osobom, które opublikowały ten pomysł przed Tobą. A to jest tak banalne rozszerzenie przyjętej odpowiedzi, że nie warto się tym przejmować.
  • Pomysł polegał na stworzeniu aliasu. Nie ' nie widziałem tej odpowiedzi wcześniej.
  • i druga rzecz ze stosu: ” Dziękujemy za opinię! Głosy oddane przez osoby o reputacji poniżej 15 są rejestrowane, ale nie zmieniają publicznie wyświetlanej oceny postów. ”

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *