Ricerca…


introduzione

Il comando di cut è un modo rapido per estrarre parti di righe di file di testo. Appartiene ai più vecchi comandi Unix. Le sue implementazioni più popolari sono la versione GNU trovata su Linux e la versione di FreeBSD che si trova su MacOS, ma ogni gusto di Unix ha il suo. Vedi sotto per le differenze. Le righe di input vengono lette da stdin o da file elencati come argomenti sulla riga di comando.

Sintassi

  • cut -f1,3 # estrae il primo e il terzo campo delimitato da tabulazioni (da stdin)

  • cut -f1-3 # estratto dal primo fino al terzo campo (fine inclusa)

  • cut -f-3 # -3 è interpretato come 1-3

  • cut -f2- # 2- viene interpretato dal secondo all'ultimo

  • cut -c1-5,10 # estratto da stdin i caratteri nelle posizioni 1,2,3,4,5,10

  • cut -s -f1 # sopprime le linee che non contengono delimitatori

  • cut --complement -f3 # (solo GNU cut) estrae tutti i campi tranne il terzo

Parametri

Parametro Dettagli
-f, --fields Selezione basata sul campo
-d, --delimiter Delimitatore per selezione basata su campo
-c, - caratteri Selezione basata sui caratteri, delimitatore ignorato o errore
-s, --only-delimited Elimina le linee senza caratteri delimitatori (altrimenti stampato)
--complemento Selezione invertita (estrai tutto tranne campi / caratteri specificati
--output-delimitatore Specificare quando deve essere diverso dal delimitatore di input

Osservazioni

1. Differenze di sintassi

Le lunghe opzioni nella tabella sopra sono supportate solo dalla versione GNU.

2. Nessun personaggio riceve un trattamento speciale

FreeBSD cut (che viene fornito con MacOS, ad esempio) non ha l' --complement e, nel caso degli intervalli di caratteri, si può usare invece il comando colrm :

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

  $ colrm 3 5 <<<"123456789"
  126789

Tuttavia, c'è una grande differenza, perché colrm tratta i caratteri TAB (ASCII 9) come tabulazioni reali fino al prossimo multiplo di otto, e i backspaces (ASCII 8) come -1 di larghezza; al contrario, cut considera tutti i caratteri come una colonna larga.

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

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

3. (Ancora no) Internazionalizzazione

Quando cut è stato progettato, tutti i personaggi sono stati a lungo un byte e l'internazionalizzazione non era un problema. Quando si scrivono sistemi con caratteri più ampi, la soluzione adottata da POSIX è stata quella di eseguire il diting tra il vecchio switch -c , che dovrebbe mantenere il suo significato di selezione dei caratteri, indipendentemente dal numero di byte, e di introdurre un nuovo switch -b che dovrebbe selezionare i byte, indipendentemente dalla codifica dei caratteri corrente. Nelle implementazioni più popolari, -b stato introdotto e funziona, ma -c funziona ancora esattamente come -b e non come dovrebbe. Ad esempio con GNU cut :

Sembra che il filtro antispam di SE inserisca in blacklist testi inglesi con caratteri kanji isolati. Non sono riuscito a superare questa limitazione, quindi i seguenti esempi sono meno espressivi di quanto potrebbero essere.

  # 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...

Se i tuoi personaggi sono al di fuori dell'intervallo ASCII e vuoi usare cut , dovresti sempre essere consapevole della larghezza dei caratteri nella tua codifica e usare di conseguenza -b . Se e quando -c inizia a funzionare come documentato, non dovrai modificare i tuoi script.

4. Confronti di velocità

i limiti del cut hanno persone che dubitano della sua utilità. In effetti, la stessa funzionalità può essere raggiunta con utility più potenti e più popolari. Tuttavia, il vantaggio di cut è la sua prestazione . Vedi sotto per alcuni confronti di velocità. test.txt ha tre milioni di righe, ognuna con cinque campi separati dallo spazio. Per il test awk , mawk stato usato mawk , perché è più veloce di GNU awk . La shell stessa (ultima riga) è di gran lunga il peggiore. I tempi indicati (in secondi) sono ciò che il comando time fornisce in tempo reale .

(Giusto per evitare equivoci: tutti i comandi testati hanno dato lo stesso risultato con l'input dato, ma ovviamente non sono equivalenti e darebbero output diversi in situazioni diverse, in particolare se i campi fossero delimitati da un numero variabile di spazi)

Comando Tempo
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. Pagine man referenziali

Utilizzo di base

L'utilizzo tipico è con file di tipo CSV, in cui ogni riga è composta da campi separati da un delimitatore, specificato dall'opzione -d . Il delimitatore predefinito è il carattere TAB. Supponiamo di avere un file di dati data.txt con linee simili

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

Poi

# 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

Come al solito, ci possono essere spazi opzionali tra uno switch e il suo parametro: -d, è lo stesso di -d ,

GNU cut consente di specificare un'opzione --output-delimiter : (una caratteristica indipendente di questo esempio è che un punto e virgola come delimitatore di input deve essere sfuggito per evitare il suo trattamento speciale da parte della shell)

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

Solo un carattere delimitatore

Non puoi avere più di un delimitatore: se specifichi qualcosa come -d ",;:" , alcune implementazioni useranno solo il primo carattere come delimitatore (in questo caso, la virgola). Altre implementazioni (es. GNU cut ) daranno un messaggio di errore

$ 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.

I delimitatori ripetuti sono interpretati come campi vuoti

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

è piuttosto ovvio, ma con stringhe delimitate da spazi potrebbe essere meno ovvio per alcuni

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

cut non può essere usato per analizzare gli argomenti come fanno la shell e altri programmi.

Nessuna citazione

Non c'è modo di proteggere il delimitatore. I fogli di calcolo e un software di gestione CSV simile in genere sono in grado di riconoscere un carattere di citazione del testo che consente di definire stringhe contenenti un delimitatore. Con il cut non puoi.

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

Estrazione, non manipolazione

È possibile estrarre solo parti di linee, non riordinare o ripetere campi.

$ 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow