Bash
Polecenie cięcia
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