Szukaj…


Wprowadzenie

Polecenie cut to szybki sposób na wyodrębnienie części wierszy plików tekstowych. Należy do najstarszych poleceń Uniksa. Najbardziej popularnymi implementacjami są wersja GNU znaleziona w systemie Linux i FreeBSD w systemie MacOS, ale każdy smak Uniksa ma swój własny. Patrz różnice poniżej. Wiersze wejściowe są odczytywane ze stdin lub z plików wymienionych jako argumenty w wierszu poleceń.

Składnia

  • Wytnij -f1,3 # Wyodrębnij pierwsze i trzecie pole rozdzielane tabulatorami (ze standardowego wejścia)

  • cut -f1-3 # ekstrakt z pierwszego do trzeciego pola (dołączone końce)

  • cut -f-3 # -3 interpretowane jest jako 1-3

  • cut -f2- # 2- jest interpretowany jako od drugiego do ostatniego

  • wytnij -c1-5,10 # wyciąg ze standardowych znaków na pozycjach 1,2,3,4,5,10

  • cut -s -f1 # pomija linie nie zawierające ograniczników

  • cut --complement -f3 # (tylko GNU cut) wyodrębnij wszystkie pola oprócz trzeciego

Parametry

Parametr Detale
-f, --fields Wybór w terenie
-d, --delimiter Ogranicznik do wyboru opartego na polu
-c, - znaki Wybór oparty na znakach, ignorowany separator lub błąd
-s, - tylko ograniczone Pomiń wiersze bez znaków ogranicznika (wydrukowane tak, jak jest inaczej)
--komplement Odwrócony wybór (wyodrębnij wszystkie oprócz określonych pól / znaków
--output-delimiter Określ, kiedy ma się różnić od ogranicznika wejściowego

Uwagi

1. Różnice w składni

Długie opcje w powyższej tabeli są obsługiwane tylko przez wersję GNU.

2. Żadna postać nie jest traktowana specjalnie

cut FreeBSD (na przykład w systemie MacOS) nie ma przełącznika --complement , aw przypadku zakresów znaków można zamiast tego colrm polecenia colrm :

  $ cut --complement -c3-5 <<<"123456789"
  126789

  $ colrm 3 5 <<<"123456789"
  126789

Jest jednak duża różnica, ponieważ colrm traktuje znaki TAB (ASCII 9) jako rzeczywiste tabulacje do następnej wielokrotności ośmiu, a odstępy (ASCII 8) jako -1; przeciwnie, cut traktuje wszystkie znaki jako szerokość jednej kolumny.

  $ colrm  3 8 <<<$'12\tABCDEF' # Input string has an embedded TAB
  12ABCDEF

  $ cut --complement -c3-8 <<<$'12\tABCDEF'
  12F

3. (Nadal nie) internacjonalizacja

Kiedy zaprojektowano cut , wszystkie znaki miały długość jednego bajta, a internacjonalizacja nie stanowiła problemu. Kiedy pisanie systemów z szerszymi znakami stało się popularne, rozwiązaniem przyjętym przez POSIX było rozróżnienie między starym przełącznikiem -c , który powinien zachować znaczenie wybierania znaków, bez względu na liczbę bajtów, oraz wprowadzenie nowego przełącznika -b który powinien wybierz bajty, niezależnie od bieżącego kodowania znaków. W najbardziej popularnych implementacjach -b został wprowadzony i działa, ale -c nadal działa dokładnie tak jak -b a nie tak, jak powinien. Na przykład z cut GNU:

Wygląda na to, że filtr antyspamowy SE umieszcza na angielskich tekstach pojedyncze znaki kanji. Nie mogłem przezwyciężyć tego ograniczenia, więc poniższe przykłady są mniej wyraziste niż mogłyby być.

  # In an encoding where each character in the input string is three bytes wide,
  # Selecting bytes 1-6 yields the first two characters (correct)
  $ LC_ALL=ja_JP.UTF-8 cut -b1-6 kanji.utf-8.txt
  ...first two characters of each line...
  

  # Selecting all three characters with the -c switch doesn’t work.
  # It behaves like -b, contrary to documentation.
  $ LC_ALL=ja_JP.UTF-8 cut -c1-3 kanji.utf-8.txt
  ...first character of each line...

  # In this case, an illegal UTF-8 string is produced.
  # The -n switch would prevent this, if implemented.
  $ LC_ALL=ja_JP.UTF-8 cut -n -c2 kanji.utf-8.txt
  ...second byte, which is an illegal UTF-8 sequence...

Jeśli twoje postacie są poza zakresem ASCII i chcesz użyć cut , zawsze powinieneś być świadomy szerokości znaków w swoim kodowaniu i stosuj odpowiednio -b . Jeśli i kiedy -c zacznie działać zgodnie z dokumentacją, nie będziesz musiał zmieniać swoich skryptów.

4. Porównania prędkości

Ograniczenia cut powodują, że ludzie wątpią w ich przydatność. W rzeczywistości tę samą funkcjonalność można uzyskać dzięki bardziej wydajnym i popularnym narzędziom. Zaletą cut jest jednak jego wydajność . Zobacz poniżej porównania prędkości. test.txt ma trzy miliony linii, z których każda zawiera pięć pól oddzielonych spacjami. Do testu awk użyto mawk , ponieważ jest on szybszy niż GNU awk . Sama powłoka (ostatnia linia) jest zdecydowanie najgorzej wydajna. Podane czasy (w sekundach) są tym, co polecenie time podaje jako czas rzeczywisty .

(Aby uniknąć nieporozumień: wszystkie testowane polecenia dały taki sam wynik przy podanym wejściu, ale oczywiście nie są one równoważne i dawałyby różne wyniki w różnych sytuacjach, w szczególności jeśli pola byłyby rozdzielone zmienną liczbą spacji)

Komenda Czas
cut -d ' ' -f1,2 test.txt 1.138s
awk '{print $1 $2}' test.txt 1,688s
join -a1 -o1.1,1.2 test.txt /dev/null 1,767s
perl -lane 'print "@F[1,2]"' test.txt 11,390s
grep -o '^\([^ ]*\) \([^ ]*\)' test.txt 22,925s
sed -e 's/^\([^ ]*\) \([^ ]*\).*$/\1 \2/' test.txt 52,122s
while read ab _; do echo $a $b; done <test.txt 55,582s

5. Referencyjne strony podręcznika man

Podstawowe użycie

Typowe użycie dotyczy plików typu CSV, gdzie każda linia składa się z pól oddzielonych separatorem, określonych przez opcję -d . Domyślnym ogranicznikiem jest znak TAB. Załóżmy, że masz plik danych data.txt z liniami podobnymi

0 0 755 1482941948.8024
102 33 4755 1240562224.3205
1003 1 644 1219943831.2367

Następnie

# extract the third space-delimited field
$ cut -d ' ' -f3 data.txt
755
4755
644

# extract the second dot-delimited field
$ cut -d. -f2 data.txt    
8024
3205
2367

# extract the character range from the 20th through the 25th character
$ cut -c20-25 data.txt 
948.80
056222    
943831

Jak zwykle mogą istnieć opcjonalne spacje między przełącznikiem a jego parametrem: -d, jest taki sam jak -d ,

cut GNU pozwala na określenie opcji --output-delimiter : (niezależną cechą tego przykładu jest to, że średnik jako separator wejściowy musi być --output-delimiter ucieczki, aby uniknąć specjalnego traktowania przez powłokę)

$ cut --output-delimiter=, -d\; -f1,2 <<<"a;b;c;d"
a,b

Tylko jeden znak ogranicznika

Nie możesz mieć więcej niż jednego separatora: jeśli podasz coś takiego jak -d ",;:" , niektóre implementacje użyją tylko pierwszego znaku jako separatora (w tym przypadku przecinka). Inne implementacje (np. cut GNU) dadzą pojawia się komunikat o błędzie.

$ cut -d ",;:" -f2 <<<"J.Smith,1 Main Road,cell:1234567890;land:4081234567"
cut: the delimiter must be a single character
Try `cut --help' for more information.

Wielokrotne ograniczniki są interpretowane jako puste pola

$ cut -d, -f1,3 <<<"a,,b,c,d,e"
a,b

jest raczej oczywiste, ale w przypadku łańcuchów rozdzielanych spacjami może być dla niektórych mniej oczywiste

$ cut -d ' ' -f1,3 <<<"a  b c d e"
a b

cut nie może być używany do parsowania argumentów, tak jak robi to powłoka i inne programy.

Bez cytowania

Nie ma sposobu, aby chronić ogranicznik. Arkusze kalkulacyjne i podobne oprogramowanie do obsługi CSV zwykle mogą rozpoznać znak cytowania tekstu, co umożliwia zdefiniowanie ciągów zawierających separator. Przy cut nie możesz.

$ cut -d, -f3 <<<'John,Smith,"1, Main Street"'
"1

Wyodrębnianie, nie manipulowanie

Możesz wyodrębniać tylko części linii, a nie zmieniać kolejności lub powtarzać pola.

$ cut -d, -f2,1 <<<'John,Smith,USA' ## Just like -f1,2
John,Smith
$ cut -d, -f2,2 <<<'John,Smith,USA' ## Just like -f2
Smith


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow