Jak sprawić, by polecenie „cut” traktowało te same sekwencyjne separatory jak jedno?

307

Próbuję wyodrębnić pewne (czwarte) pole ze strumienia tekstu opartego na kolumnach, dostosowanego do miejsca. Próbuję użyć cutpolecenia w następujący sposób:

cat text.txt | cut -d " " -f 4

Niestety cutnie traktuje kilku spacji jako jednego separatora. Mógłbym przepuścić przez awk

awk '{ printf $4; }'

lub sed

sed -E "s/[[:space:]]+/ /g"

zwinąć przestrzenie, ale chciałbym wiedzieć, czy jest jakiś sposób na radzenie sobie cuti kilku separatorów natywnie?

mbaitoff
źródło
12
AWK jest właściwą drogą.
Wstrzymano do odwołania.
Możliwa duplikat pomocy dla linux cut - jak określić więcej spacji dla separatora?
Inanc Gumus

Odpowiedzi:

545

Próbować:

tr -s ' ' <text.txt | cut -d ' ' -f4

Ze strony podręcznika tr:

-s, --squeeze-repeats zastępuje każdą sekwencję wejściową powtarzanego znaku
                        który jest wymieniony w SET1 z jednym wystąpieniem
                        tej postaci
kev
źródło
24
Nie ma cattu potrzeby . Możesz przejść < text.txtbezpośrednio do tr. en.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat
arielf
1
Nie jestem pewien, czy jest to prostsze, ale zamierzasz scalić, możesz zrezygnować z cięć -di tłumaczyć bezpośrednio z wielu znaków na tabulator. Na przykład: przyszedłem tutaj, aby znaleźć sposób na automatyczne wyeksportowanie mojego wyświetlacza:who am i | tr -s ' ()' '\t' | cut -f5
Leo
Nie usuwa to wiodących / końcowych białych znaków (które mogą, ale nie muszą być pożądane, ale zwykle nie są), w przeciwieństwie do rozwiązania awk. Rozwiązanie awk jest również znacznie bardziej czytelne i mniej szczegółowe.
n.caillou
-1 OSTRZEŻENIE: TO NIE JEST TO SAMO RZECZ JAKO TRAKTOWANIE SEKWENCJONALNYCH DELIMETRÓW JAKO JEDEN. Porównaj echo "a b c" | cut -d " " -f2-,echo "a b c" | tr -s " " | cut -d " " -f2-
user541686,
96

Jak komentujesz w swoim pytaniu, awkjest to naprawdę droga. Używanie cutjest możliwe razem z tr -swyciskaniem spacji, jak pokazuje odpowiedź Kev .

Pozwól mi jednak przejść przez wszystkie możliwe kombinacje dla przyszłych czytelników. Objaśnienia znajdują się w części Test.

tr | skaleczenie

tr -s ' ' < file | cut -d' ' -f4

awk

awk '{print $4}' file

grzmotnąć

while read -r _ _ _ myfield _
do
   echo "forth field: $myfield"
done < file

sed

sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file

Testy

Biorąc pod uwagę ten plik, przetestujmy polecenia:

$ cat a
this   is    line     1 more text
this      is line    2     more text
this    is line 3     more text
this is   line 4            more    text

tr | skaleczenie

$ cut -d' ' -f4 a
is
                        # it does not show what we want!


$ tr -s ' ' < a | cut -d' ' -f4
1
2                       # this makes it!
3
4
$

awk

$ awk '{print $4}' a
1
2
3
4

grzmotnąć

To odczytuje pola sekwencyjnie. Używając _tego, wskazujemy, że jest to zmienna jednorazowa jako „zmienna śmieciowa”, aby zignorować te pola. W ten sposób przechowujemy $myfieldjako czwarte pole w pliku, bez względu na odstępy między nimi.

$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4

sed

Przechwytuje trzy grupy spacji i nie ma spacji z ([^ ]*[ ]*){3}. Następnie łapie wszystko, co nadchodzi, do spacji jako czwartego pola, na którym jest w końcu drukowane \1.

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4
fedorqui „SO przestań szkodzić”
źródło
2
awkjest nie tylko elegancki i prosty, ale także zawarty w VMware ESXi, w którym go trbrakuje.
użytkownik121391
2
@ user121391 jeszcze jeden powód do korzystania awk!
fedorqui „SO przestań szkodzić”
@fedorqui Nigdy nie słyszałem o podkreśleniu jako o „zmiennej śmieciowej”. Czy możesz podać więcej informacji na ten temat?
BryKKan
1
@BryKKan Dowiedziałem się o tym w Greg's Jak mogę odczytać plik (strumień danych, zmienna) wiersz po wierszu (i / lub pole po polu)? : Niektóre osoby używają zmiennej odchodzącej _ jako „zmiennej śmieciowej”, aby zignorować pola. To (lub rzeczywiście dowolna zmienna) może być również użyte więcej niż raz w jednym readpoleceniu, jeśli nie obchodzi nas, co się w nim dzieje . Może być cokolwiek, tylko że w jakiś sposób stało się standardem zamiast junk_varlub whatever:)
fedorqui „Więc przestań krzywdzić”
25

najkrótsze / najbardziej przyjazne rozwiązanie

Po sfrustrowaniu zbyt wieloma ograniczeniami cut, napisałem własny zamiennik, który wezwałem cutsdo „zmniejszenia sterydów”.

cięcia zapewnia najbardziej minimalistyczne rozwiązanie tego i wielu innych powiązanych problemów z wycinaniem / wklejaniem.

Jednym z wielu przykładów jest odpowiedź na to pytanie:

$ cat text.txt
0   1        2 3
0 1          2   3 4

$ cuts 2 text.txt
2
2

cuts obsługuje:

  • automatyczne wykrywanie najczęstszych ograniczników pól w plikach (+ możliwość zastąpienia wartości domyślnych)
  • ograniczniki dopasowane do wielu znaków, znaków mieszanych i wyrażeń regularnych
  • wyodrębnianie kolumn z wielu plików z mieszanymi ogranicznikami
  • przesunięcia od końca linii (przy użyciu liczb ujemnych) oprócz początku linii
  • automatyczne wklejanie kolumn obok siebie (nie trzeba wywoływać pasteosobno)
  • obsługa zmiany kolejności w terenie
  • plik konfiguracyjny, w którym użytkownicy mogą zmienić swoje osobiste preferencje
  • duży nacisk na łatwość obsługi i minimalistyczne wymagane pisanie

i wiele więcej. Żaden z nich nie jest dostarczany standardowo cut.

Zobacz też: https://stackoverflow.com/a/24543231/1296044

Źródło i dokumentacja (darmowe oprogramowanie): http://arielf.github.io/cuts/

arielf
źródło
4

Ten linijka Perla pokazuje, jak blisko Perl jest powiązany z awk:

perl -lane 'print $F[3]' text.txt

Jednak @Ftablica autosplit zaczyna się od indeksu, $F[0]a pola awk zaczynają się od$1

Chris Koknat
źródło
3

W wersjach, o cutktórych wiem, nie, nie jest to możliwe. cutjest przede wszystkim przydatny do analizowania plików, w których separator nie jest spacją (na przykład /etc/passwd) i które mają stałą liczbę pól. Dwa separatory w rzędzie oznaczają puste pole, i dotyczy to również białych znaków.

Benoit
źródło