Bash
Snittkommandot
Sök…
Introduktion
Den cut
kommando är ett snabbt sätt att extrahera delar av rader av textfiler. Det tillhör de äldsta Unix-kommandona. De mest populära implementeringarna är GNU-versionen som finns på Linux och FreeBSD-versionen som finns på MacOS, men varje smak av Unix har sin egen. Se nedan för skillnader. Inmatningsraderna läses antingen från stdin
eller från filer som listas som argument på kommandoraden.
Syntax
klipp -f1,3 # extrakt första och tredje flikavgränsade fält (från stdin)
klipp -f1-3 # extrakt från första upp till tredje fält (slutar ingår)
klipp -f-3 # -3 tolkas som 1-3
cut -f2- # 2- tolkas som från den andra till den sista
skär -c1-5,10 # extrakt från stdin karaktärerna i positionerna 1,2,3,4,5,10
cut -s -f1 # undertryck rader som inte innehåller avgränsare
klipp - komplement -f3 # (endast GNU-klipp) extrahera alla fält utom det tredje
parametrar
Parameter | detaljer |
---|---|
-f, - fält | Fältbaserat urval |
-d, - avgränsare | Avgränsare för fältbaserat urval |
-c, - tecken | Teckenbaserat urval, ignorerad avgränsare eller fel |
-s, - bara avgränsad | Undertryck rader utan tecken för avgränsning (skrivs ut som annars) |
--komplement | Inverterat val (extrahera alla utom angivna fält / tecken |
--output-avgränsare | Ange när det måste skilja sig från ingångsavgränsaren |
Anmärkningar
1. Syntaxskillnader
Långa alternativ i tabellen ovan stöds endast av GNU-versionen.
2. Ingen karaktär får specialbehandling
FreeBSD- cut
(som till exempel levereras med MacOS) har inte --complement
, och när det gäller colrm
istället använda colrm
kommandot:
$ cut --complement -c3-5 <<<"123456789"
126789
$ colrm 3 5 <<<"123456789"
126789
Det finns emellertid en stor skillnad, eftersom colrm
behandlar TAB-tecken (ASCII 9) som verkliga tabeller upp till nästa multipel av åtta, och bakutrymmen (ASCII 8) som -1 breda; tvärtom, cut
behandlar alla tecken som en kolumn bred.
$ colrm 3 8 <<<$'12\tABCDEF' # Input string has an embedded TAB
12ABCDEF
$ cut --complement -c3-8 <<<$'12\tABCDEF'
12F
3. (Fortfarande nej) Internationalisering
När cut
utformades var alla karaktärer en byte lång och internationalisering var inte ett problem. När skrivsystem med bredare tecken blev populära var lösningen som antogs av POSIX att skilja mellan den gamla -c
omkopplaren, som borde behålla sin betydelse att välja tecken, oavsett hur många byte breda, och att införa en ny switch -b
som borde välj byte, oavsett aktuell teckenkodning. I de mest populära implementeringarna introducerades och fungerar -b
, men -c
fungerar fortfarande exakt som -b
och inte som det borde. Till exempel med GNU- cut
:
Det verkar som om SE: s spamfilter svartlistor engelska texter med isolerade kanji-tecken i dem. Jag kunde inte övervinna denna begränsning, så följande exempel är mindre uttrycksfulla än de kunde vara.
# 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...
Om dina karaktärer ligger utanför ASCII-intervallet och du vill använda cut
, bör du alltid vara medveten om teckenbredden i din kodning och använda -b
. Om och när -c
börjar fungera som dokumenterat behöver du inte ändra dina skript.
4. Hastighetsjämförelser
cut
begränsningar gör att människor tvivlar på dess användbarhet. Faktum är att samma funktionalitet kan uppnås med kraftfullare och mer populära verktyg. Men cut
är 's fördel dess prestanda. Se nedan för några hastighetsjämförelser. test.txt
har tre miljoner rader, med fem rymdseparerade fält vardera. För awk
testet användes mawk
eftersom det är snabbare än GNU awk
. Själva skalet (sista raden) är den överlägset värsta utövaren. Tiderna (i sekunder) är vad time
kommandot ger som realtid.
(Bara för att undvika missförstånd: alla testade kommandon gav samma utgång med den givna ingången, men de är naturligtvis inte likvärdiga och skulle ge olika utgångar i olika situationer, särskilt om fälten avgränsades av ett variabelt antal utrymmen)
Kommando | Tid |
---|---|
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. Referens man sidor
Grundläggande användning
Den typiska användningen är med filer av CSV-typ, där varje rad består av fält separerade med en avgränsare, specificerad av alternativet -d
. Standardavgränsaren är TAB-tecknet. Anta att du har en datafil data.txt
med rader som
0 0 755 1482941948.8024
102 33 4755 1240562224.3205
1003 1 644 1219943831.2367
Sedan
# 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
Som vanligt kan det finnas valfria mellanrum mellan en switch och dess parameter: -d,
är samma som -d ,
GNU- cut
gör det möjligt att specificera ett --output-delimiter
: (en oberoende funktion i detta exempel är att en semikolon som ingångsavgränsare måste undkommas för att undvika dess speciella behandling av skalet)
$ cut --output-delimiter=, -d\; -f1,2 <<<"a;b;c;d"
a,b
Endast en avgränsande karaktär
Du kan inte ha mer än en avgränsare: om du anger något som -d ",;:"
kommer vissa implementationer bara att använda det första tecknet som en avgränsare (i detta fall komma.) Andra implementationer (t.ex. GNU- cut
) kommer att ge du ett felmeddelande.
$ 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.
Upprepade avgränsare tolkas som tomma fält
$ cut -d, -f1,3 <<<"a,,b,c,d,e"
a,b
är ganska uppenbart, men med rumsavgränsade strängar kan det vara mindre uppenbart för vissa
$ cut -d ' ' -f1,3 <<<"a b c d e"
a b
cut
kan inte användas för att analysera argument som skalet och andra program gör.
Ingen offert
Det finns inget sätt att skydda avgränsaren. Kalkylark och liknande CSV-hanteringsprogramvara kan vanligtvis känna igen ett textcitationstecken som gör det möjligt att definiera strängar som innehåller en avgränsare. Med cut
du inte.
$ cut -d, -f3 <<<'John,Smith,"1, Main Street"'
"1
Extrahera, inte manipulera
Du kan bara extrahera delar av rader, inte ordna om eller upprepa fält.
$ cut -d, -f2,1 <<<'John,Smith,USA' ## Just like -f1,2
John,Smith
$ cut -d, -f2,2 <<<'John,Smith,USA' ## Just like -f2
Smith