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 lubt
znaków, a ' jest tym, co GNUsed
działa również wtedy, gdyPOSIXLY_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. Odpowiedzised
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 efektread
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 poleceniatr
, 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. ”