Comando para enviar el contenido del archivo a stdout?

28

Sé que catpuede hacer esto, pero su objetivo principal es concatenar en lugar de solo mostrar el contenido.

También sé sobre lessy more, pero estoy buscando algo simple ( no un buscapersonas ) que simplemente envíe el contenido de un archivo al terminal y esté hecho específicamente para esto, si existe tal cosa.

confundido00
fuente
1
En realidad, el 99% de las veces que usa cat es para mostrar archivos en lugar de concatenar algo.
LatinSuD
1
@LatinSuD - 100% del tiempo - catconcatena.
mikeserv
@mikeserv: Es una cuestión de lo que quieres decir al realizar una operación; El uso normal del lenguaje implicaría que se hace al menos una vez. "Imprimir" una cadena vacía no implica imprimir ningún carácter; Sería justo decir que no está imprimiendo nada. Ahora la computación a+b+cimplica realizar 2 adiciones, y la computación ano implica agregar nada. Del mismo modo, la ejecución cat fno implica concatenar nada (aunque esto sea lo único que podría significar "concatenar una secuencia de un archivo").
Marc van Leeuwen
2
@mikeserv: No entiendo lo que quieres decir con entrada + salida. Seguro catlee un archivo y escribe otro archivo (secuencia), pero eso no significa que se concatena nada. Si quieres decir que cat frealmente está funcionando cat - f, eso simplemente no es cierto.
Marc van Leeuwen
1
@ confused00: catrealmente estaba destinado a concatenar ( cat file1 file2concatenará ambos archivos a stdout). Pero su efecto secundario es que, cuando solo tiene 1 archivo como argumento, genera ese único archivo en stdout (donde sea que vaya, ya sea su terminal o redirigido a algo). Por lo tanto, no se creó ningún otro comando solo para generar en stdout, como catexistía y lo permitió simplemente. Por lo tanto, quieres usar cat.
Olivier Dulac

Respuestas:

37

El más obvio es cat. Pero, también eche un vistazo a heady tail. También hay otros utillities shell para imprimir un archivo línea por línea: sed, awk, grep. Pero esos son para alternar el contenido del archivo o para buscar dentro del archivo.

Hice algunas pruebas para estimar cuál es la más efectiva. Corro todo el canal stracepara ver cuál hizo menos llamadas al sistema. Mi archivo tiene 1275 líneas.

  • awk: 1355 llamadas al sistema
  • cat: 51 llamadas al sistema
  • grep: 1337 llamadas al sistema
  • head: 93 llamadas al sistema
  • tail: 130 llamadas al sistema
  • sed: 1378 llamadas al sistema

Como puede ver, incluso si catfue diseñado para concatenar archivos, es el más rápido y efectivo. sed, awkY el grepimpreso del archivo línea por línea, por eso tienen más que 1275 llamadas al sistema.

caos
fuente
8
¡Buena idea contar los syscalls!
Jan
1
+1, la respuesta es más precisa (sobre el significado del gato), más completa (alternativas) e investigada (syscalls)
Olivier Dulac
23

Sé que catpuede hacer esto, pero su objetivo principal es concatenar en lugar de solo mostrar el contenido.

El propósito de cates exactamente eso, leer un archivo y enviarlo a stdout.

ene
fuente
1
Pero cat --helpdice "Concatenar ARCHIVO (s), o entrada estándar, a la salida estándar". No quiero concatenar nada
confundido00
18
Lo creas o no, el gato es exactamente lo que estás buscando de todos modos.
Jan
55
No, @ confundido00, Jan tiene razón. La cosa es que el terminal es estándar, ¿lo ves? hazlo, readlink /dev/fd/1por ejemplo: deberías poner el nombre de tu tty allí si se ejecuta en un indicador estándar. Entonces, concatenar entrada a salida es lo que está pidiendo hacer.
mikeserv
2
@mikeserv Sí, entiendo tu punto, supongo que estaba demasiado fijo en el significado de 'concatenar'.
confused00
3
La lógica es que imprimir el contenido de un archivo es solo un caso especial de imprimir el contenido de uno o más archivos en secuencia.
zwol
10

Primero, catescribe en la salida estándar, que no es necesariamente un terminal, incluso si catse escribió como parte de un comando en un shell interactivo. Si realmente necesita algo para escribir en el terminal, incluso cuando se redirige la salida estándar, eso no es tan fácil (necesita especificar qué terminal, y puede que ni siquiera haya uno si el comando se ejecuta desde un script), aunque uno podría (ab) usar la salida de error estándar si el comando es simplemente una parte de una tubería. Pero dado que usted indicó que catrealmente hace el trabajo, supongo que no estaba preguntando sobre tal situación.

Si su propósito fuera enviar lo que está escrito a la salida estándar en una tubería, entonces el uso catsería elegible para el Premio de uso inútil de Cat , ya que cat file | pipeline(donde se pipelineencuentra cualquier tubería) se puede hacer de manera más eficiente <file pipeline. Pero de nuevo, de su redacción deduzco que esta no era su intención.

Por lo tanto, no está tan claro de qué se preocupa. Si encuentra catdemasiado tiempo para escribir, puede definir un alias de uno o dos caracteres (todavía hay algunos nombres que permanecen sin usar en Unix estándar). Sin embargo, si te preocupa catgastar ciclos inútiles, no deberías.

Si hubiera un programa nullque no toma argumentos y solo copia la entrada estándar a la salida estándar (el objeto neutral para las tuberías), puede hacer lo que quiera <file null. No existe tal programa, aunque sería fácil de escribir (un programa en C con solo una función de una línea mainpuede hacer el trabajo), pero llamar catsin argumentos (o cat -si desea ser explícito) hace exactamente eso.

Si hubo un nocatprograma que toma exactamente un argumento de nombre de archivo, intenta abrir el archivo, se queja si no puede, y de lo contrario procede a copiar desde el archivo a la salida estándar, entonces eso sería justo lo que está pidiendo. Es solo un poco más difícil de escribir que null, el trabajo principal es abrir el archivo, probar y posiblemente quejarse (si es meticuloso, también puede incluir una prueba de que exista exactamente un argumento, y quejarse de lo contrario). Pero nuevamente cat, ahora provisto de un argumento único, hace exactamente eso, por lo que no hay necesidad de ningún nocatprograma.

Una vez que logró escribir el nocatprograma, ¿por qué detenerse en un solo argumento? Envolver el código en un bucle for(;*argp!=NULL;++argp)realmente no es ningún esfuerzo, agrega como máximo un par de instrucciones de máquina al binario y evita tener que quejarse de un número incorrecto de argumentos (lo que ahorra muchas más instrucciones). Voilà una versión primitiva de cat, concatenando archivos. (Para ser honesto, necesita ajustarlo un poco para que sin argumentos se comporte como null).

Por supuesto, en el catprograma real , agregaron algunas campanas y silbatos, porque siempre lo hacen. Pero la esencia es que el aspecto de "concatenación" de los catcostos realmente no supone ningún esfuerzo, ni para el programador ni para la máquina que lo ejecuta. El hecho de que catsubsume nully nocatexplica la inexistencia de tales programas. Evite usar catcon un solo argumento si el resultado entra en una tubería, pero si se usa solo para mostrar el contenido del archivo en el terminal, incluso la página a la que enlacé admite que este es un uso útil cat, así que no lo dude.


Puede probar que catrealmente se implementa mediante un bucle simple alrededor de una nocatfuncionalidad hipotética , llamando catcon varios nombres de archivo entre los que se encuentra un nombre no válido, no en la primera posición: en lugar de quejarse de inmediato de que este archivo no existe, catprimero se elimina el precedente archivos válidos, y luego se queja sobre el archivo no válido (al menos así es como se comporta mi gato).

Marc van Leeuwen
fuente
7

Bajo zshprueba

<file

Creo que es la forma más corta de imprimir un archivo. Utiliza 'oculto' cat(o moresi stdout es un terminal), pero el comando utilizado para imprimir está controlado por una READNULLCMDvariable que puede sobrescribir de forma segura directamente por el nombre del comando o incluso por alguna función. Por ejemplo, para imprimir archivos con numeración de línea:

numcat() { nl -s'> ' -w2 - }
READNULLCMD=numcat
<file
jimmij
fuente
5

POSIX define gato como:

NOMBRE

cat - concatenar e imprimir archivos

SINOPSIS

gato [-u] [archivo ...]

DESCRIPCIÓN

La utilidad cat leerá los archivos en secuencia y escribirá su contenido en la salida estándar en la misma secuencia.

Así que creo que concatenar aquí significa leer archivos en secuencia .

Cuonglm
fuente
5

Sé que esta es una pregunta en tiempo pasado. Técnicamente, dado que imprimir el contenido de un archivo stdoutes una forma de concatenación, cates semánticamente apropiado. No olvide que printftiene la intención semántica de formatear e imprimir datos. Bash también proporciona sintaxis para redirigir la entrada y la salida de los archivos. Una combinación de estos podría producir esto:

printf '%s' "$(<file.txt)"
James M. Lay
fuente
44
Además de ser particularmente indirecta, el comando que se muestra no es equivalente a cat file.txt, ya que eliminará cualquier nueva línea final ( $(...)esto hace esto).
Marc van Leeuwen
+1, buena captura. No sabía eso.
James M. Lay
3

Usando bashbuiltins y evitando la creación de subprocesos:

{ while IFS='' read -rd '' _bcat_; do printf '%s\0' "${_bcat_}"; done; printf '%s' "${_bcat_}"; unset _bcat_; } <'/path/to/file'

IFSse aplicará solo al readcomando, así que no se preocupe por sus IFScambios globales .

Se requiere bucle para manejar caracteres nulos (gracias a Stéphane Chazelas).

De esta manera, no es adecuado para archivos grandes porque el contenido del archivo se lee primero en la variable (por lo tanto, la memoria). Por cierto, he intentado imprimir un archivo de texto de 39M de esta manera y el uso de la memoria bash no superó los 5M, por lo que no estoy seguro de este caso.

También es muy lento y la CPU es ineficiente: para el mismo archivo de 39M, tomó ~ 3 minutos con el 100% de uso de un solo núcleo.

Para archivos grandes o binarios, mejor usar cat '/path/to/file'o incluso dd if='/path/to/file' bs=1Msi es posible.

Mikhail
fuente
1
Vea también pv -qqué en Linux puede usar splice()cuál para algunos tipos de stdin / stdout mejorará el rendimiento.
Stéphane Chazelas
1

Solo como una demostración, puedes hacer

cp foo /dev/stdout
wisbucky
fuente