4 Utilizzo essenziale e pratico del comando Cut in Linux
Il comando cut in Linux consente di rimuovere dati su ogni riga di un file. Leggi questo tutorial per sapere come utilizzarlo in modo efficace per elaborare file di testo o dati CSV.
Il comando cut è lo strumento canonico per rimuovere “colonne” da un file di testo. In questo contesto una “colonna” può essere definita come un intervallo di caratteri o byte identificati dalla loro posizione fisica sulla riga, oppure un intervallo di campi delimitati da un separatore.
Ho scritto in precedenza sull'utilizzo dei comandi AWK. In questa guida dettagliata, spiegherò quattro esempi essenziali e pratici di comando cut in Linux che ti aiuteranno alla grande.
4 Esempi pratici di comando Cut in Linux
Se preferisci puoi guardare questo video che spiega gli stessi esempi pratici di comando cut che ho elencato nell'articolo.
1. Lavorare con intervalli di caratteri
Quando richiamato con l'opzione della riga di comando -c
, il comando cut rimuoverà gli intervalli di caratteri.
Come qualsiasi altro filtro, il comando cut non modifica il file di input sul posto ma copierà i dati modificati sul suo output standard. È tua responsabilità reindirizzare l'output del comando su un file per salvare il risultato o utilizzare una pipe per inviarlo come input a un altro comando.
Se hai scaricato i file di test di esempio utilizzati nel video sopra, puoi vedere il file di dati BALANCE.txt
, proveniente direttamente da un software di contabilità che mia moglie utilizza al lavoro:
sh$ head BALANCE.txt
ACCDOC ACCDOCDATE ACCOUNTNUM ACCOUNTLIB ACCDOCLIB DEBIT CREDIT
4 1012017 623477 TIDE SCHEDULE ALNEENRE-4701-LOC 00000001615,00
4 1012017 445452 VAT BS/ENC ALNEENRE-4701-LOC 00000000323,00
4 1012017 4356 PAYABLES ALNEENRE-4701-LOC 00000001938,00
5 1012017 623372 ACCOMODATION GUIDE ALNEENRE-4771-LOC 00000001333,00
5 1012017 445452 VAT BS/ENC ALNEENRE-4771-LOC 00000000266,60
5 1012017 4356 PAYABLES ALNEENRE-4771-LOC 00000001599,60
6 1012017 4356 PAYABLES FACT FA00006253 - BIT QUIROBEN 00000001837,20
6 1012017 445452 VAT BS/ENC FACT FA00006253 - BIT QUIROBEN 00000000306,20
6 1012017 623795 TOURIST GUIDE BOOK FACT FA00006253 - BIT QUIROBEN 00000001531,00
Questo è un file di testo a larghezza fissa poiché i campi dati sono riempiti con un numero variabile di spazi per garantire che vengano visualizzati come una tabella ben allineata.
Come corollario, una colonna di dati inizia e termina sempre nella stessa posizione del carattere su ciascuna riga. C'è però un piccolo trabocchetto: nonostante il nome, il comando cut
in realtà richiede di specificare l'intervallo di dati che si desidera mantenere, non l'intervallo che desideri rimuovere. Quindi, se avessi bisogno solo delle colonne ACCOUNTNUM
e ACCOUNTLIB
nel file di dati sopra, scriverei che:
sh$ cut -c 25-59 BALANCE.txt | head
ACCOUNTNUM ACCOUNTLIB
623477 TIDE SCHEDULE
445452 VAT BS/ENC
4356 /accountPAYABLES
623372 ACCOMODATION GUIDE
445452 VAT BS/ENC
4356 PAYABLES
4356 PAYABLES
445452 VAT BS/ENC
623795 TOURIST GUIDE BOOK
Cos'è un intervallo?
Come abbiamo appena visto, il comando cut richiede di specificare l'intervallo di dati che vogliamo conservare. Quindi, introduciamo più formalmente cos'è un intervallo: per il comando cut
, un intervallo è definito da una posizione iniziale e finale separate da un trattino. Gli intervalli sono in base 1, ovvero il primo elemento della riga è l'elemento numero 1, non 0. Gli intervalli sono inclusivi: l'inizio e la fine verranno conservati nell'output, così come tutti i caratteri tra di loro. È un errore specificare un intervallo la cui posizione finale è precedente (“inferiore”) alla sua posizione iniziale. Come scorciatoia, puoi omettere il valore iniziale o finale come descritto nella tabella seguente:
a-b
: l'intervallo tra a e b (incluso)a
: equivalente all'intervalloa-a
-b
: equivalente a1-a
b-
: equivalente ab-∞
I comandi di taglio consentono di specificare diversi intervalli separandoli con una virgola. Qui ci sono un paio di esempi:
# Keep characters from 1 to 24 (inclusive)
cut -c -24 BALANCE.txt
# Keep characters from 1 to 24 and 36 to 59 (inclusive)
cut -c -24,36-59 BALANCE.txt
# Keep characters from 1 to 24, 36 to 59 and 93 to the end of the line (inclusive)
cut -c -24,36-59,93- BALANCE.txt
Una limitazione (o caratteristica, a seconda di come la vedi) del comando cut
è che non riordinerà mai i dati. Pertanto, il comando seguente produrrà esattamente lo stesso risultato del precedente, nonostante gli intervalli siano specificati in un ordine diverso:
cut -c 93-,-24,36-59 BALANCE.txt
Puoi verificarlo facilmente utilizzando il comando diff
:
diff -s <(cut -c -24,36-59,93- BALANCE.txt) \
<(cut -c 93-,-24,36-59 BALANCE.txt)
Files /dev/fd/63 and /dev/fd/62 are identical
Allo stesso modo, il comando cut
non duplica mai i dati:
# One might expect that could be a way to repeat
# the first column three times, but no...
cut -c -10,-10,-10 BALANCE.txt | head -5
ACCDOC
4
4
4
5
Vale la pena menzionare che è stata proposta un'opzione -o
per eliminare queste due ultime limitazioni, consentendo all'utilità cut
di riordinare o duplicare i dati. Ma questo è stato respinto dal comitato POSIX“perché questo tipo di miglioramento non rientra nell'ambito della bozza dello standard IEEE P1003.2b. "
Per quanto mi riguarda, non conosco alcuna versione tagliata che implementi tale proposta come estensione. Ma se lo fai, per favore, condividilo con noi usando la sezione commenti!
2. Lavorare con intervalli di byte
Quando richiamato con l'opzione della riga di comando -b
, il comando cut rimuoverà gli intervalli di byte.
A prima vista, non c'è alcuna differenza evidente tra gli intervalli di caratteri e byte:
sh$ diff -s <(cut -b -24,36-59,93- BALANCE.txt) \
<(cut -c -24,36-59,93- BALANCE.txt)
Files /dev/fd/63 and /dev/fd/62 are identical
Questo perché il mio file di dati di esempio utilizza la codifica dei caratteri US-ASCII ("charset") poiché il comando file -i
può indovinarlo correttamente:
sh$ file -i BALANCE.txt
BALANCE.txt: text/plain; charset=us-ascii
In quella codifica dei caratteri, esiste una mappatura uno a uno tra caratteri e byte. Usando un solo byte, puoi teoricamente codificare fino a 256 caratteri diversi (cifre, lettere, segni di punteggiatura, simboli, ... ). In pratica, quel numero è molto più basso poiché le codifiche dei caratteri prevedono alcuni valori speciali (come i 32 o 65 caratteri di controllo generalmente riscontrabile). In ogni caso, anche se potessimo utilizzare l’intero intervallo di byte, ciò sarebbe ben lungi dall’essere sufficiente per memorizzare la varietà della scrittura umana. Quindi, oggi, la mappatura uno a uno tra caratteri e byte è più un'eccezione che la norma ed è quasi sempre sostituita dall'onnipresente codifica multibyte UTF-8. Vediamo ora come il comando cut può gestirlo.
Lavorare con caratteri multibyte
Come ho detto in precedenza, i file di dati di esempio utilizzati come esempio per quell'articolo provengono da un software di contabilità utilizzato da mia moglie. Sembra che abbia aggiornato il software di recente e, successivamente, i file di testo esportati erano leggermente diversi. Ti lascio provare a individuare la differenza da solo:
sh$ head BALANCE-V2.txt
ACCDOC ACCDOCDATE ACCOUNTNUM ACCOUNTLIB ACCDOCLIB DEBIT CREDIT
4 1012017 623477 TIDE SCHEDULE ALNÉENRE-4701-LOC 00000001615,00
4 1012017 445452 VAT BS/ENC ALNÉENRE-4701-LOC 00000000323,00
4 1012017 4356 PAYABLES ALNÉENRE-4701-LOC 00000001938,00
5 1012017 623372 ACCOMODATION GUIDE ALNÉENRE-4771-LOC 00000001333,00
5 1012017 445452 VAT BS/ENC ALNÉENRE-4771-LOC 00000000266,60
5 1012017 4356 PAYABLES ALNÉENRE-4771-LOC 00000001599,60
6 1012017 4356 PAYABLES FACT FA00006253 - BIT QUIROBEN 00000001837,20
6 1012017 445452 VAT BS/ENC FACT FA00006253 - BIT QUIROBEN 00000000306,20
6 1012017 623795 TOURIST GUIDE BOOK FACT FA00006253 - BIT QUIROBEN 00000001531,00
Il titolo di questa sezione potrebbe aiutarti a scoprire cosa è cambiato. Ma, trovato o no, vediamo ora le conseguenze di quel cambiamento:
sh$ cut -c 93-,-24,36-59 BALANCE-V2.txt
ACCDOC ACCDOCDATE ACCOUNTLIB DEBIT CREDIT
4 1012017 TIDE SCHEDULE 00000001615,00
4 1012017 VAT BS/ENC 00000000323,00
4 1012017 PAYABLES 00000001938,00
5 1012017 ACCOMODATION GUIDE 00000001333,00
5 1012017 VAT BS/ENC 00000000266,60
5 1012017 PAYABLES 00000001599,60
6 1012017 PAYABLES 00000001837,20
6 1012017 VAT BS/ENC 00000000306,20
6 1012017 TOURIST GUIDE BOOK 00000001531,00
19 1012017 SEMINAR FEES 00000000080,00
19 1012017 PAYABLES 00000000080,00
28 1012017 MAINTENANCE 00000000746,58
28 1012017 VAT BS/ENC 00000000149,32
28 1012017 PAYABLES 00000000895,90
31 1012017 PAYABLES 00000000240,00
31 1012017 VAT BS/DEBIT 00000000040,00
31 1012017 ADVERTISEMENTS 00000000200,00
32 1012017 WATER 00000000202,20
32 1012017 VAT BS/DEBIT 00000000020,22
32 1012017 WATER 00000000170,24
32 1012017 VAT BS/DEBIT 00000000009,37
32 1012017 PAYABLES 00000000402,03
34 1012017 RENTAL COSTS 00000000018,00
34 1012017 PAYABLES 00000000018,00
35 1012017 MISCELLANEOUS CHARGES 00000000015,00
35 1012017 VAT BS/DEBIT 00000000003,00
35 1012017 PAYABLES 00000000018,00
36 1012017 LANDLINE TELEPHONE 00000000069,14
36 1012017 VAT BS/ENC 00000000013,83
Ho copiato sopra l'output del comando in-extenso quindi dovrebbe essere ovvio che qualcosa è andato storto con l'allineamento delle colonne.
La spiegazione è che il file di dati originale conteneva solo caratteri US-ASCII (simboli, segni di punteggiatura, numeri e lettere latine senza segni diacritici)
Ma se osservi attentamente il file prodotto dopo l'aggiornamento del software, puoi vedere che il nuovo file di dati di esportazione ora conserva le lettere accentate. Ad esempio, la società denominata “ALNÉENRE” ora è scritta correttamente mentre in precedenza veniva esportata come “ALNEENRE” (senza accento)
L'utilità file -i
non ha mancato questa modifica poiché ora segnala il file come codificato UTF-8:
sh$ file -i BALANCE-V2.txt
BALANCE-V2.txt: text/plain; charset=utf-8
Per vedere come vengono codificate le lettere accentate in un file UTF-8, possiamo utilizzare l'utilità hexdump
che ci permette di guardare direttamente i byte in un file:
# To reduce clutter, let's focus only on the second line of the file
sh$ sed '2!d' BALANCE-V2.txt
4 1012017 623477 TIDE SCHEDULE ALNÉENRE-4701-LOC 00000001615,00
sh$ sed '2!d' BALANCE-V2.txt | hexdump -C
00000000 34 20 20 20 20 20 20 20 20 20 31 30 31 32 30 31 |4 101201|
00000010 37 20 20 20 20 20 20 20 36 32 33 34 37 37 20 20 |7 623477 |
00000020 20 20 20 54 49 44 45 20 53 43 48 45 44 55 4c 45 | TIDE SCHEDULE|
00000030 20 20 20 20 20 20 20 20 20 20 20 41 4c 4e c3 89 | ALN..|
00000040 45 4e 52 45 2d 34 37 30 31 2d 4c 4f 43 20 20 20 |ENRE-4701-LOC |
00000050 20 20 20 20 20 20 20 20 20 20 20 20 20 30 30 30 | 000|
00000060 30 30 30 30 31 36 31 35 2c 30 30 20 20 20 20 20 |00001615,00 |
00000070 20 20 20 20 20 20 20 20 20 20 20 0a | .|
0000007c
Sulla riga 00000030 dell'output hexdump
, dopo una serie di spazi (byte 20
), puoi vedere:
la lettera
A
è codificata come byte41
,la lettera
L
è codificata nel byte4c
,e la lettera
N
è codificata come byte4e
.
Ma la LETTERA LATINA MAIUSCOLA E CON ACUTO (poiché è il nome ufficiale della lettera É nello standard Unicode) è codificata utilizzando due byte c3 89
Ed ecco il problema: usare il comando cut
con intervalli espressi come posizioni di byte funziona bene per le codifiche a lunghezza fissa, ma non per quelle a lunghezza variabile come UTF-8 o Shift JIS. Ciò è chiaramente spiegato nel seguente estratto non normativo dello standard POSIX:
Le versioni precedenti dell'utilità cut funzionavano in un ambiente in cui byte e caratteri erano considerati equivalenti (elaborazione modulo
e <tab> in alcune implementazioni). Nel mondo esteso dei caratteri multibyte è stata aggiunta la nuova opzione -b.
Ehi, aspetta un attimo! Non stavo usando l'opzione -b
nell'esempio "difettoso" sopra, ma l'opzione -c
. Quindi non avrebbe dovuto funzionare?!?
Sì, dovrebbe: è un peccato, ma siamo nel 2018 e nonostante ciò, a partire da GNU Coreutils 8.30, l'implementazione GNU dell'utilità cut non gestisce ancora il multi caratteri -byte correttamente. Per citare la documentazione GNU, l'opzione -c
è "Lo stesso di -b per ora, ma l'internazionalizzazione cambierà questo[... ] " — una menzione che è presente da più di 10 anni ormai!
D'altra parte, l'implementazione OpenBSD dell'utilità cut è conforme a POSIX e rispetterà le impostazioni locali correnti per gestire correttamente i caratteri multibyte:
# Ensure subseauent commands will know we are using UTF-8 encoded
# text files
openbsd-6.3$ export LC_CTYPE=en_US.UTF-8
# With the `-c` option, cut works properly with multi-byte characters
openbsd-6.3$ cut -c -24,36-59,93- BALANCE-V2.txt
ACCDOC ACCDOCDATE ACCOUNTLIB DEBIT CREDIT
4 1012017 TIDE SCHEDULE 00000001615,00
4 1012017 VAT BS/ENC 00000000323,00
4 1012017 PAYABLES 00000001938,00
5 1012017 ACCOMODATION GUIDE 00000001333,00
5 1012017 VAT BS/ENC 00000000266,60
5 1012017 PAYABLES 00000001599,60
6 1012017 PAYABLES 00000001837,20
6 1012017 VAT BS/ENC 00000000306,20
6 1012017 TOURIST GUIDE BOOK 00000001531,00
19 1012017 SEMINAR FEES 00000000080,00
19 1012017 PAYABLES 00000000080,00
28 1012017 MAINTENANCE 00000000746,58
28 1012017 VAT BS/ENC 00000000149,32
28 1012017 PAYABLES 00000000895,90
31 1012017 PAYABLES 00000000240,00
31 1012017 VAT BS/DEBIT 00000000040,00
31 1012017 ADVERTISEMENTS 00000000200,00
32 1012017 WATER 00000000202,20
32 1012017 VAT BS/DEBIT 00000000020,22
32 1012017 WATER 00000000170,24
32 1012017 VAT BS/DEBIT 00000000009,37
32 1012017 PAYABLES 00000000402,03
34 1012017 RENTAL COSTS 00000000018,00
34 1012017 PAYABLES 00000000018,00
35 1012017 MISCELLANEOUS CHARGES 00000000015,00
35 1012017 VAT BS/DEBIT 00000000003,00
35 1012017 PAYABLES 00000000018,00
36 1012017 LANDLINE TELEPHONE 00000000069,14
36 1012017 VAT BS/ENC 00000000013,83
Come previsto, quando si utilizza la modalità byte -b
invece della modalità carattere -c
, l'implementazione cut di OpenBSD si comporta come la versione cut
legacy:
openbsd-6.3$ cut -b -24,36-59,93- BALANCE-V2.txt
ACCDOC ACCDOCDATE ACCOUNTLIB DEBIT CREDIT
4 1012017 TIDE SCHEDULE 00000001615,00
4 1012017 VAT BS/ENC 00000000323,00
4 1012017 PAYABLES 00000001938,00
5 1012017 ACCOMODATION GUIDE 00000001333,00
5 1012017 VAT BS/ENC 00000000266,60
5 1012017 PAYABLES 00000001599,60
6 1012017 PAYABLES 00000001837,20
6 1012017 VAT BS/ENC 00000000306,20
6 1012017 TOURIST GUIDE BOOK 00000001531,00
19 1012017 SEMINAR FEES 00000000080,00
19 1012017 PAYABLES 00000000080,00
28 1012017 MAINTENANCE 00000000746,58
28 1012017 VAT BS/ENC 00000000149,32
28 1012017 PAYABLES 00000000895,90
31 1012017 PAYABLES 00000000240,00
31 1012017 VAT BS/DEBIT 00000000040,00
31 1012017 ADVERTISEMENTS 00000000200,00
32 1012017 WATER 00000000202,20
32 1012017 VAT BS/DEBIT 00000000020,22
32 1012017 WATER 00000000170,24
32 1012017 VAT BS/DEBIT 00000000009,37
32 1012017 PAYABLES 00000000402,03
34 1012017 RENTAL COSTS 00000000018,00
34 1012017 PAYABLES 00000000018,00
35 1012017 MISCELLANEOUS CHARGES 00000000015,00
35 1012017 VAT BS/DEBIT 00000000003,00
35 1012017 PAYABLES 00000000018,00
36 1012017 LANDLINE TELEPHONE 00000000069,14
36 1012017 VAT BS/ENC 00000000013,83
3. Lavorare con i campi
In un certo senso, lavorare con i campi in un file di testo delimitato è più semplice per l'utilità cut
, poiché dovrà solo individuare i delimitatori di campo (un byte) su ogni riga, copiando poi alla lettera il contenuto del campo all'output senza preoccuparsi di eventuali problemi di codifica.
Ecco un esempio di file di testo delimitato:
sh$ head BALANCE.csv
ACCDOC;ACCDOCDATE;ACCOUNTNUM;ACCOUNTLIB;ACCDOCLIB;DEBIT;CREDIT
4;1012017;623477;TIDE SCHEDULE;ALNEENRE-4701-LOC;00000001615,00;
4;1012017;445452;VAT BS/ENC;ALNEENRE-4701-LOC;00000000323,00;
4;1012017;4356;PAYABLES;ALNEENRE-4701-LOC;;00000001938,00
5;1012017;623372;ACCOMODATION GUIDE;ALNEENRE-4771-LOC;00000001333,00;
5;1012017;445452;VAT BS/ENC;ALNEENRE-4771-LOC;00000000266,60;
5;1012017;4356;PAYABLES;ALNEENRE-4771-LOC;;00000001599,60
6;1012017;4356;PAYABLES;FACT FA00006253 - BIT QUIROBEN;;00000001837,20
6;1012017;445452;VAT BS/ENC;FACT FA00006253 - BIT QUIROBEN;00000000306,20;
6;1012017;623795;TOURIST GUIDE BOOK;FACT FA00006253 - BIT QUIROBEN;00000001531,00;
Potresti conoscere il formato file come CSV (per valori separati da virgole), anche se il separatore di campo non è sempre una virgola. Ad esempio, il punto e virgola (;
) viene spesso utilizzato come separatore di campo ed è spesso la scelta predefinita quando si esportano dati come "CSV" nei paesi che già utilizzano la virgola come separatore decimale ( come facciamo in Francia - da qui la scelta di quel carattere nel mio file di esempio). Un'altra variante popolare utilizza un carattere di tabulazione come separatore di campo, producendo quello che a volte viene chiamato file di valori separati da tabulazione. Infine, nel mondo Unix e Linux, i due punti (:
) sono un altro separatore di campo relativamente comune che potresti trovare, ad esempio, nello standard /etc/passwd
e File /etc/group
.
Quando utilizzi un formato di file di testo delimitato, fornisci al comando cut l'intervallo di campi da mantenere utilizzando l'opzione -f
e devi specificare il delimitatore utilizzando -d
opzione (senza l'opzione -d
, l'utilità di taglio utilizza per impostazione predefinita un carattere di tabulazione per il separatore):
sh$ cut -f 5- -d';' BALANCE.csv | head
ACCDOCLIB;DEBIT;CREDIT
ALNEENRE-4701-LOC;00000001615,00;
ALNEENRE-4701-LOC;00000000323,00;
ALNEENRE-4701-LOC;;00000001938,00
ALNEENRE-4771-LOC;00000001333,00;
ALNEENRE-4771-LOC;00000000266,60;
ALNEENRE-4771-LOC;;00000001599,60
FACT FA00006253 - BIT QUIROBEN;;00000001837,20
FACT FA00006253 - BIT QUIROBEN;00000000306,20;
FACT FA00006253 - BIT QUIROBEN;00000001531,00;
Gestione delle righe che non contengono il delimitatore
Ma cosa succede se qualche riga nel file di input non contiene il delimitatore? È forte la tentazione di immaginarlo come una riga contenente solo il primo campo. Ma questo non fa l'utilità cut.
Per impostazione predefinita, quando si utilizza l'opzione -f
, l'utilità cut restituirà sempre testualmente una riga che non contiene il delimitatore (probabilmente presupponendo che si tratti di una riga non di dati come un'intestazione o un commento di qualche tipo ):
sh$ (echo "# 2018-03 BALANCE"; cat BALANCE.csv) > BALANCE-WITH-HEADER.csv
sh$ cut -f 6,7 -d';' BALANCE-WITH-HEADER.csv | head -5
# 2018-03 BALANCE
DEBIT;CREDIT
00000001615,00;
00000000323,00;
;00000001938,00
Usando l'opzione -s
, puoi invertire questo comportamento, quindi cut
ignorerà sempre tale riga:
sh$ cut -s -f 6,7 -d';' BALANCE-WITH-HEADER.csv | head -5
DEBIT;CREDIT
00000001615,00;
00000000323,00;
;00000001938,00
00000001333,00;
Se hai voglia di hacker, puoi sfruttare questa funzionalità come un modo relativamente oscuro per mantenere solo le righe contenenti un determinato carattere:
# Keep lines containing a `e`
sh$ printf "%s\n" {mighty,bold,great}-{condor,monkey,bear} | cut -s -f 1- -d'e'
Modifica del delimitatore di output
Come estensione, l'implementazione GNU di cut consente di utilizzare un diverso separatore di campo per l'output utilizzando l'opzione --output-delimiter
:
sh$ cut -f 5,6- -d';' --output-delimiter="*" BALANCE.csv | head
ACCDOCLIB*DEBIT*CREDIT
ALNEENRE-4701-LOC*00000001615,00*
ALNEENRE-4701-LOC*00000000323,00*
ALNEENRE-4701-LOC**00000001938,00
ALNEENRE-4771-LOC*00000001333,00*
ALNEENRE-4771-LOC*00000000266,60*
ALNEENRE-4771-LOC**00000001599,60
FACT FA00006253 - BIT QUIROBEN**00000001837,20
FACT FA00006253 - BIT QUIROBEN*00000000306,20*
FACT FA00006253 - BIT QUIROBEN*00000001531,00*
Si noti, in tal caso, che vengono sostituite tutte le occorrenze del separatore di campo e non solo quelle al limite degli intervalli specificati negli argomenti della riga di comando.
4. Estensioni GNU non POSIX
Parlando di estensioni GNU non POSIX, un paio di esse possono essere particolarmente utili. Vale la pena ricordare che le seguenti estensioni funzionano altrettanto bene con byte, caratteri (per cosa significa nell'attuale implementazione GNU) o intervalli di campi:--complement
Pensa a questa opzione come al punto esclamativo in un indirizzo sed (!
); invece di mantenere i dati corrispondenti all'intervallo specificato, cut
manterrà i dati NON corrispondenti all'intervallo
# Keep only field 5
sh$ cut -f 5 -d';' BALANCE.csv |head -3
ACCDOCLIB
ALNEENRE-4701-LOC
ALNEENRE-4701-LOC
# Keep all but field 5
sh$ cut --complement -f 5 -d';' BALANCE.csv |head -3
ACCDOC;ACCDOCDATE;ACCOUNTNUM;ACCOUNTLIB;DEBIT;CREDIT
4;1012017;623477;TIDE SCHEDULE;00000001615,00;
4;1012017;445452;VAT BS/ENC;00000000323,00;
--terminato con zero
(-z
)
utilizzare il carattere NUL come terminatore di riga anziché il carattere di nuova riga. L'opzione -z
è particolarmente utile quando i tuoi dati possono contenere caratteri di nuova riga incorporati, come quando lavori con i nomi di file (poiché la nuova riga è un carattere valido in un nome di file, ma NUL non lo è).
Per mostrarti come funziona l'opzione -z
, facciamo un piccolo esperimento. Per prima cosa creeremo un file il cui nome contiene nuove righe incorporate:
bash$ touch
Supponiamo ora di voler visualizzare i primi 5 caratteri di ciascun nome di file *.txt
. Una soluzione ingenua fallirà miseramente qui:
sh$ ls -1 *.txt | cut -c 1-5
BALAN
BALAN
EMPTY
FILE
WITH
NAME.
Potresti aver già letto che ls
è stato progettato per il consumo umano e utilizzarlo in una pipeline di comandi è un anti-pattern (lo è infatti). Quindi usiamo invece il comando find:
sh$ find . -name '*.txt' -printf "%f\n" | cut -c 1-5
BALAN
EMPTY
FILE
WITH
NAME.
BALAN
e ... che ha prodotto fondamentalmente lo stesso risultato errato di prima (sebbene in un ordine diverso perché ls
ordina implicitamente i nomi dei file, cosa che il comando find
non fa).
Il problema è che in entrambi i casi il comando cut
non può fare la distinzione tra un carattere di nuova riga che fa parte di un campo dati (il nome del file) e un carattere di nuova riga utilizzato come indicatore di fine record. Ma, utilizzando il byte NUL (\0
) come terminatore di riga si elimina la confusione in modo da poter finalmente ottenere il risultato atteso:
# I was told (?) some old versions of tr require using \000 instead of \0
# to denote the NUL character (let me know if you needed that change!)
sh$ find . -name '*.txt' -printf "%f\0" | cut -z -c 1-5| tr '\0' '\n'
BALAN
EMPTY
BALAN
Con quest'ultimo esempio ci stiamo allontanando dal nocciolo di questo articolo, ovvero il comando cut
. Quindi, ti lascerò provare a capire da solo il significato del strano "%f\0"
dopo l'argomento printf del comando find o perché ho usato il comando tr alla fine della pipeline .
Si può fare molto di più con il comando Taglia
Ho appena mostrato l'utilizzo più comune e, a mio avviso, più essenziale del comando Taglia. Puoi applicare il comando in modi ancora più pratici. Dipende dal tuo ragionamento logico e dalla tua immaginazione.
Non esitare a utilizzare la sezione commenti qui sotto per pubblicare i tuoi risultati. E, come sempre, se ti piace questo articolo, non dimenticare di condividerlo sui tuoi siti e social media preferiti!