El comando de corte es la herramienta canónica para eliminar "columnas" de un archivo de texto. En este contexto, una “columna” se puede definir como un rango de caracteres o bytes identificados por su posición física en la línea, o un rango de campos delimitados por un separador.
He escrito sobre el uso de comandos AWK anteriormente. En esta guía detallada, explicaré cuatro ejemplos esenciales y prácticos del comando de corte en Linux que te serán de gran ayuda.
4 Ejemplos practicos del comando Cortar en Linux
Si lo prefiere, puede ver este video que explica los mismos ejemplos prácticos de comando de corte que he enumerado en el artículo.
1. Trabajando con rangos de caracteres
Cuando se invoca con -c
opción de línea de comando, el comando de corte eliminará carácter rangos.
Como cualquier otro filtro, el comando de corte no cambia el archivo de entrada pero copiará los datos modificados a su salida estándar. Es su responsabilidad redirigir la salida del comando a un archivo para guardar el resultado o usar una canalización para enviarlo como entrada a otro comando.
Si ha descargado los archivos de prueba de muestra utilizados en el video anterior, puede ver el BALANCE.txt
archivo de datos, que proviene directamente de un software de contabilidad que mi esposa usa en su trabajo:
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
Este es un archivo de texto de ancho fijo ya que los campos de datos se rellenan con un número variable de espacios para garantizar que se muestren como una tabla bien alineada.
Como corolario, una columna de datos siempre comienza y termina en la misma posición de carácter en cada línea. Sin embargo, hay un pequeño escollo:a pesar de su nombre, el cut
El comando en realidad requiere que especifique el rango de datos que desea conservar , no el intervalo que desea eliminar . Entonces, si necesito solo el ACCOUNTNUM
y ACCOUNTLIB
columnas en el archivo de datos anterior, escribiría eso:
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
¿Qué es un rango?
Como acabamos de ver, el comando de corte requiere que especifiquemos el rango de datos que queremos conservar. Entonces, introduzcamos más formalmente qué es un rango:para el cut
comando, un rango se define por una posición inicial y final separadas por un guión. Los rangos se basan en 1, es decir, el primer elemento de la línea es el elemento número 1, no 0. Los rangos son inclusivos:el inicio y el final se conservarán en la salida, así como todos los caracteres entre ellos. Es un error especificar un rango cuya posición final está antes ("inferior") que su posición inicial. Como atajo, puede omitir el inicio o valor final como se describe en la siguiente tabla:
a-b
:el rango entre a y b (inclusive)a
:equivalente al rangoa-a
-b
:equivalente a1-a
b-
:equivalente ab-∞
Los comandos de corte le permiten especificar varios rangos separándolos con una coma. Aquí hay un par de ejemplos:
# 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 limitación (o característica, según se mire) del cut
comando es que nunca reordenará los datos . Entonces, el siguiente comando producirá exactamente el mismo resultado que el anterior, a pesar de que los rangos se especifican en un orden diferente:
cut -c 93-,-24,36-59 BALANCE.txt
Puede verificar eso fácilmente usando el diff
comando:
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
Del mismo modo, el cut
comando nunca duplica datos :
# 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 mencionar que hubo una propuesta para un -o
opción de levantar esas dos últimas limitaciones, permitiendo el cut
utilidad para reordenar o duplicar datos. Pero esto fue rechazado por el comité POSIX"porque este tipo de mejora está fuera del alcance del borrador del estándar IEEE P1003.2b".
Por mi parte, no conozco ninguna versión cortada que implemente esa propuesta como una extensión. Pero si lo hace, por favor, ¡compártalo con nosotros usando la sección de comentarios!
2. Trabajando con rangos de bytes
Cuando se invoca con -b
opción de línea de comando, el comando de corte eliminará byte rangos.
A primera vista, no hay una diferencia obvia entre personaje y byte rangos:
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
Esto se debe a que mi archivo de datos de muestra usa la codificación de caracteres US-ASCII ("juego de caracteres") como file -i
comando puede adivinarlo correctamente:
sh$ file -i BALANCE.txt
BALANCE.txt: text/plain; charset=us-ascii
En esa codificación de caracteres, hay un mapeo uno a uno entre caracteres y bytes. Usando solo un byte, teóricamente puede codificar hasta 256 caracteres diferentes (dígitos, letras, signos de puntuación, símbolos, etc.). generalmente encontrado). De todos modos, incluso si pudiéramos usar el rango de bytes completo, eso estaría lejos de ser suficiente para almacenar la variedad de escritura humana. Entonces, hoy en día, el mapeo uno a uno entre caracteres y bytes es más la excepción que la norma y casi siempre se reemplaza por la omnipresente codificación multibyte UTF-8. Veamos ahora cómo el comando de corte podría manejar eso.
Trabajando con caracteres multibyte
Como dije anteriormente, los archivos de datos de muestra utilizados como ejemplos para ese artículo provienen de un software de contabilidad utilizado por mi esposa. Agrega que actualizó ese software recientemente y, después de eso, los archivos de texto exportados fueron sutilmente diferentes. Te dejo que intentes encontrar la diferencia por ti mismo:
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
El título de esta sección puede ayudarlo a encontrar lo que ha cambiado. Pero, encontrado o no, veamos ahora las consecuencias de ese cambio:
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
He copiado arriba la salida del comando in-extenso por lo que debería ser obvio que algo salió mal con la alineación de la columna.
La explicación es que el archivo de datos original contenía solo caracteres US-ASCII (símbolos, puntuaciones, números y letras latinas sin marcas diacríticas)
Pero si observa detenidamente el archivo producido después de la actualización del software, puede ver que el nuevo archivo de datos de exportación ahora conserva las letras acentuadas. Por ejemplo, la empresa denominada "ALNÉENRE" ahora está correctamente escrita mientras que anteriormente se exportaba como "ALNEENRE" (sin acento)
El archivo file -i
La utilidad no se perdió ese cambio ya que ahora informa que el archivo está codificado en UTF-8:
sh$ file -i BALANCE-V2.txt
BALANCE-V2.txt: text/plain; charset=utf-8
Para ver cómo se codifican las letras acentuadas en un archivo UTF-8, podemos usar el hexdump
utilidad que nos permite mirar directamente los bytes en un archivo:
# 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
En la línea 00000030 del hexdump
salida, después de un montón de espacios (byte 20
), puedes ver:
- la letra
A
está codificado como el byte41
, - la letra
L
está codificado en el byte4c
, - y la letra
N
está codificado como el byte4e
.
Pero, la LETRA E MAYÚSCULA LATINA MAYÚSCULA CON AGUDA (ya que es el nombre oficial de la letra É en el estándar Unicode) se codifica con dos bytes c3 89
Y aquí está el problema:usar el cut
El comando con rangos expresados como posiciones de bytes funciona bien para codificaciones de longitud fija, pero no para codificaciones de longitud variable como UTF-8 o Shift JIS. Esto se explica claramente en el siguiente extracto no normativo del estándar POSIX:
Las versiones anteriores de la utilidad de corte funcionaban en un entorno en el que los bytes y los caracteres se consideraban equivalentes (procesamiento de móduloy en algunas implementaciones). En el mundo extendido de los caracteres de varios bytes, se ha agregado la nueva opción -b.
¡Oye, espera un minuto! No estaba usando -b
opción en el ejemplo "defectuoso" anterior, pero el -c
opción. Entonces, no debería que han funcionado?!?
Sí, debería :es lamentable, pero estamos en 2018 y, a pesar de eso, a partir de GNU Coreutils 8.30, la implementación de GNU de la utilidad de corte todavía no maneja correctamente los caracteres de varios bytes. Para citar la documentación de GNU, el -c
la opción es “Lo mismo que -b por ahora, pero la internacionalización cambiará eso[… ]” — ¡una mención que está presente desde hace más de 10 años!
Por otro lado, la implementación de OpenBSD de la utilidad de corte es compatible con POSIX y respetará la configuración local actual para manejar correctamente los caracteres de varios bytes:
# 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
Como era de esperar, al usar -b
modo byte en lugar de -c
modo de caracteres, la implementación de corte de OpenBSD se comporta como el cut
heredado :
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. Trabajando con campos
En cierto sentido, trabajar con campos en un archivo de texto delimitado es más fácil para el cut
utilidad, ya que solo tendrá que ubicar los delimitadores de campo (un byte) en cada fila, copiando luego palabra por palabra el contenido del campo en la salida sin preocuparse por ningún problema de codificación.
Aquí hay un archivo de texto delimitado de muestra:
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;
Es posible que conozca ese formato de archivo como CSV (por valor separado por comas), incluso si el separador de campo no siempre es una coma. Por ejemplo, el punto y coma (;
) se encuentra con frecuencia como un separador de campo, y a menudo es la opción predeterminada al exportar datos como "CSV" en países que ya usan la coma como separador decimal (como lo hacemos en Francia; de ahí la elección de ese carácter en mi archivo de muestra ). Otra variante popular utiliza un carácter de tabulación como separador de campo, produciendo lo que a veces se denomina un archivo de valores separados por tabulaciones. Finalmente, en el mundo de Unix y Linux, los dos puntos (:
) es otro separador de campo relativamente común que puede encontrar, por ejemplo, en el estándar /etc/passwd
y /etc/group
archivos.
Cuando usa un formato de archivo de texto delimitado, proporciona al comando de corte el rango de campos para seguir usando el -f
opción, y debe especificar el delimitador usando -d
opción (sin -d
opción, la utilidad de corte tiene por defecto un carácter de tabulación para el separador):
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;
Manejo de líneas que no contienen el delimitador
Pero, ¿qué pasa si alguna línea en el archivo de entrada no contiene el delimitador? Es tentador imaginar eso como una fila que contiene solo el primer campo. Pero esto no lo que hace la utilidad de corte.
Por defecto, cuando se usa -f
opción, la utilidad de corte siempre generará una línea textual que no contiene el delimitador (probablemente asumiendo que se trata de una fila sin datos, como un encabezado o un comentario de algún 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 el -s
opción, puede revertir ese comportamiento, así que cut
siempre ignorará dicha línea:
sh$ cut -s -f 6,7 -d';' BALANCE-WITH-HEADER.csv | head -5
DEBIT;CREDIT
00000001615,00;
00000000323,00;
;00000001938,00
00000001333,00;
Si está de humor para hackear, puede explotar esa función como una forma relativamente oscura de mantener solo las líneas que contienen un carácter determinado:
# Keep lines containing a `e`
sh$ printf "%s\n" {mighty,bold,great}-{condor,monkey,bear} | cut -s -f 1- -d'e'
Cambiando el delimitador de salida
Como extensión, la implementación GNU de cut permite usar un separador de campo diferente para la salida usando el --output-delimiter
opción:
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*
Observe, en ese caso, todas las apariciones del separador de campo se reemplazan, y no solo aquellas en el límite de los rangos especificados en los argumentos de la línea de comando.
4. Extensiones GNU no POSIX
Hablando de extensiones GNU no POSIX, un par de ellas que pueden ser particularmente útiles. Vale la pena mencionar que las siguientes extensiones funcionan igual de bien con bytes, caracteres (para lo que eso significa en la implementación actual de GNU) o rangos de campo:--complement
Piense en esa opción como el signo de exclamación en una dirección sed (!
); en lugar de mantener los datos que coinciden con el rango dado, cut
mantendrá los datos que NO coincidan con el rango
# 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;
--zero-terminated
(-z
)
utilice el carácter NUL como terminador de línea en lugar del carácter de nueva línea. El -z
La opción es particularmente útil cuando sus datos pueden contener caracteres de nueva línea incrustados, como cuando se trabaja con nombres de archivo (dado que la nueva línea es un carácter válido en un nombre de archivo, pero NUL no lo es).
Para mostrarle cómo -z
la opción funciona, hagamos un pequeño experimento. Primero, crearemos un archivo cuyo nombre contenga nuevas líneas incrustadas:
bash$ touch
Supongamos ahora que quiero mostrar los primeros 5 caracteres de cada *.txt
nombre del archivo. Una solución ingenua fallará miserablemente aquí:
sh$ ls -1 *.txt | cut -c 1-5
BALAN
BALAN
EMPTY
FILE
WITH
NAME.
Es posible que ya hayas leído ls
fue diseñado para el consumo humano, y usarlo en una canalización de comando es un antipatrón (de hecho lo es). Así que usemos el find
comando en su lugar:
sh$ find . -name '*.txt' -printf "%f\n" | cut -c 1-5
BALAN
EMPTY
FILE
WITH
NAME.
BALAN
y... que produjo básicamente el mismo resultado erróneo que antes (aunque en un orden diferente porque ls
ordena implícitamente los nombres de archivo, algo que find
el comando no funciona).
El problema es en ambos casos, el cut
El comando no puede hacer la distinción entre un carácter de nueva línea que forma parte de un campo de datos (el nombre de archivo) y un carácter de nueva línea utilizado como marcador de fin de registro. Pero, usando el byte NUL (\0
) a medida que el terminador de línea aclara la confusión para que finalmente podamos obtener el resultado esperado:
# 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 ese último ejemplo, nos estamos alejando del núcleo de este artículo que era el cut
dominio. Entonces, dejaré que trates de averiguar por ti mismo el significado del funky "%f\0"
después de -printf
argumento del find
comando o por qué usé el tr
comando al final de la canalización.
Se puede hacer mucho más con el comando Cortar
Acabo de mostrar el uso más común y, en mi opinión, el más esencial del comando Cortar. Puede aplicar el comando de formas aún más prácticas. Depende de tu razonamiento lógico e imaginación.
No dude en utilizar la sección de comentarios a continuación para publicar sus hallazgos. Y, como siempre, si te gusta este artículo, ¡no olvides compartirlo en tus sitios web y redes sociales favoritos!