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?


12
AWK jest właściwą drogą.
Wstrzymano do odwołania.

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

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

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/


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


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.