Agarrando los primeros [x] caracteres para una cadena de una tubería

58

Si tengo una salida realmente larga de un comando (línea simple) pero sé que solo quiero los primeros [x] (digamos 8) caracteres de la salida, ¿cuál es la forma más fácil de obtener eso? No hay delimitadores.

xenoterracida
fuente
relacionado: stackoverflow.com/questions/1405611/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Respuestas:

82

Una forma es usar cut:

 command | cut -c1-8

Esto le dará los primeros 8 caracteres de cada línea de salida. Como cutes parte de POSIX, es probable que esté en la mayoría de los Unices.

Steven D
fuente
3
Tenga en cuenta que cut -cselecciona caracteres; cut -bo head -cselecciona bytes. Esto marca la diferencia en algunos entornos locales (en la práctica, cuando se usa UTF-8).
Gilles 'SO- deja de ser malvado'
Tampoco tiene que especificar el índice de inicio en este caso. El refrán cut -c-8seleccionará del personaje 1 al 8.
Sparhawk
@Steven, cutes equivalente en Windows?
Pacerier
También command | dd bs=8 count=1 2>/dev/null. No digo que sea más corto o superior. Solo otra alternativa.
dubiousjim
@Gilles, pero tenga en cuenta que con las versiones actuales de GNU cut, cut -cfunciona como cut -b(es decir, no funciona correctamente para caracteres de varios bytes).
Stéphane Chazelas
24

Estas son algunas otras formas de obtener solo los primeros 8 caracteres.

command | head -c8

command | awk '{print substr($0,1,8);exit}' 

command | sed 's/^\(........\).*/\1/;q'

Y si tienes bash

var=$(command)
echo ${var:0:8}
usuario1606
fuente
2
Creo que la siguiente formulación sed es un poco más fácil de leer: command | sed 's/\(.\{8\}\).*/\1/'o si su sed lo admite: command | sed -r 's/(.{8}).*/\1/'; De lo contrario, +1
Steven D
Cosas buenas, pero tenga en head -ccuenta que cuenta bytes , no caracteres. De manera similar, entre las principales implementaciones de Awk, solo GNU awk maneja los caracteres de varios bytes correctamente; FreeBSD Awk y Mawk no lo hacen.
mklement0
2

Si tiene un shell suficientemente avanzado (por ejemplo, lo siguiente funcionará en Bash, no estoy seguro sobre el guión), puede hacer lo siguiente:

read -n8 -d$'\0' -r <(command)

Después de ejecutar read ... <(command), tus personajes estarán en la variable de shell REPLY. Escriba help readpara conocer otras opciones.

Explicación: el -n8argumento readdice que queremos hasta 8 caracteres. El -d$'\0'dicho lee hasta un nulo, en lugar de una nueva línea. De esta manera, la lectura continuará para 8 caracteres incluso si uno de los caracteres anteriores es una nueva línea (pero no si es nulo). Una alternativa -n8 -d$'\0'es usar -N8, que lee exactamente 8 caracteres o hasta que el stdin alcanza EOF. No se honra ningún delimitador. Eso probablemente se adapte mejor a sus necesidades, pero no sé de antemano cuántos proyectiles tienen una lectura que honra -Nen lugar de honrar -ny -d. Continuando con la explicación: -rdice ignore \-escapes, de modo que, por ejemplo, tratemos \\como dos caracteres, en lugar de uno solo \.

Finalmente, lo hacemos en read ... <(command)lugar de hacerlo command | read ...porque en la segunda forma, la lectura se ejecuta en una subshell que luego se cierra inmediatamente, perdiendo la información que acaba de leer.

Otra opción es hacer todo el procesamiento dentro de la subshell. Por ejemplo:

$ echo abcdefghijklm | { read -n8 -d$'\0' -r; printf "REPLY=<%s>\n" "$REPLY"; }
REPLY=<abcdefgh>
dubiousjim
fuente
1
Si solo desea generar los 8 caracteres y no necesita procesarlos en el shell, simplemente utilícelos cut.
dubiousjim
Es bueno saberlo read -n <num>; pequeña advertencia: Bash 3.x (aún actual en el sistema operativo) interpreta erróneamente <num>como un recuento de bytes y, por lo tanto, falla con caracteres de varios bytes; Esto se ha solucionado en Bash 4.x.
mklement0
Esta es una gran y útil respuesta. Mucho más general que los demás.
not2qubit
2

Otra solución única mediante el uso de expansión de parámetros

echo ${word:0:x}

EG: word="Hello world"
echo ${word:0:3} or echo ${word::3} 
o/p: Hel


EG.2: word="Hello world"
echo ${word:1:3}
o/p: ell
Prabhat Kumar Singh
fuente
También puede usar una variable que contenga la longitud, por ejemplo: en x=8; echo ${word:0:$x}lugar de codificar el número entero.
Cometsong
1

Esto es portátil:

a="$(command)"             # Get the output of the command.
b="????"                   # as many ? as characters are needed.
echo ${a%"${a#${b}}"}      # select that many chars from $a

Construir una cadena de caracteres de longitud variable tiene su propia pregunta aquí .

Comunidad
fuente
0

Tuve este problema al generar manualmente archivos de suma de comprobación en el repositorio maven. Desafortunadamente, cut -csiempre imprime una nueva línea al final de la salida. Para suprimir que uso xxd:

command | xxd -l$BYTES | xxd -r

Produce exactamente $BYTESbytes, a menos que la commandsalida de 's sea más corta, entonces exactamente esa salida.

Krzysztof Jabłoński
fuente
otro método para despegar cutde la nueva línea final es introducirlo en:| tr -d '\n'
Cometsong