Muchas utilidades de línea de comandos pueden tomar su entrada de una tubería o como un argumento de nombre de archivo. Para scripts de shell largos, encuentro que comenzar la cadena con un cat
hace que sea más legible, especialmente si el primer comando necesitaría argumentos de varias líneas.
Comparar
sed s/bla/blaha/ data \
| grep blah \
| grep -n babla
y
cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla
¿Es este último método menos eficiente? Si es así, ¿la diferencia es suficiente para preocuparse si el script se ejecuta, por ejemplo, una vez por segundo? La diferencia en la legibilidad no es enorme.
shell-script
performance
pipe
cat
tshepang
fuente
fuente
cat
. Sin embargo, creo que la pregunta más importante aquí es la legibilidad del código, que a menudo es una prioridad sobre el rendimiento. Cuando más rápido se puede escribir más bonito , ¿por qué no? Señalar el problemacat
generalmente lleva al usuario a tener una mejor comprensión de las tuberías y los procesos en general. Vale la pena el esfuerzo para que escriban un código comprensible la próxima vez.cat
; el punto de Caleb sobre el uso de funciones y la redirección también lo resuelve.)Respuestas:
La respuesta "definitiva" es presentada por The Useless of
cat
Award .La creación de instancias de cat solo para que su código se lea de manera diferente solo genera un proceso más y un conjunto más de flujos de entrada / salida que no son necesarios. Normalmente, el retraso real en sus scripts será bucles ineficientes y procesamiento real. En la mayoría de los sistemas modernos, un extra
cat
no va a matar su rendimiento, perocasisiempre hay otra forma de escribir su código.La mayoría de los programas, como puede observar, pueden aceptar un argumento para el archivo de entrada. Sin embargo, siempre existe el shell incorporado
<
que se puede usar donde sea que se espere una secuencia STDIN que le ahorrará un proceso al hacer el trabajo en el proceso de shell que ya se está ejecutando.Incluso puedes ser creativo con DONDE lo escribes. Normalmente se colocaría al final de un comando antes de especificar cualquier redirección de salida o canalización como esta:
Pero no tiene por qué ser así. Incluso puede venir primero. Por ejemplo, su código de ejemplo podría escribirse así:
Si le preocupa la legibilidad de los scripts y su código es lo suficientemente desordenado como para agregar una línea para
cat
que sea más fácil de seguir, existen otras formas de limpiar su código. Uno que uso mucho y que ayuda a que los scripts sean fáciles de descifrar más tarde es dividir las tuberías en conjuntos lógicos y guardarlos en funciones. El código del script se vuelve muy natural y cualquier parte de la línea de canalización es más fácil de depurar.Entonces podrías continuar con
fix_blahs < data | fix_frogs | reorder | format_for_sql
. Una pipleline que se lee así es realmente fácil de seguir, y los componentes individuales se pueden depurar fácilmente en sus respectivas funciones.fuente
<file
podría venir antes de la orden. ¡Esto resuelve todos mis problemas!<file
puede venir a cualquier parte de la línea de comando:<file grep needle
ogrep <file needle
ogrep needle <file
. La excepción son comandos complejos como bucles y agrupaciones; allí la redirección debe venir después del cierredone
/}
/)
/ etc. @Caleb Esto se mantiene en todos los shells Bourne / POSIX. Y no estoy de acuerdo con que sea feo.$(cat /some/file)
con$(< /some/file)
, que hace lo mismo, pero no ofrece un proceso de desove.$(< /some/file)
es de portabilidad limitada. Funciona en bash, pero no en Ash de BusyBox, por ejemplo, o en FreeBSD sh. Probablemente tampoco funcione en el tablero, ya que esos tres últimos proyectiles son primos cercanos.Aquí hay un resumen de algunos de los inconvenientes de:
terminado
$file
arriba. En el caso decat
, eso siempre es un problema, exceptozsh
; en el caso de la redirección, eso es solo un problema parabash
oksh88
y, para algunos otros shells, solo cuando es interactivo (no en scripts).cmd
está integrado, eso es incluso 2 procesos en algunos shells comobash
.cat
está integrado, también se ejecuta un comando adicional (y, por supuesto, se carga e inicializa (y las bibliotecas a las que también está vinculado)).cat
ycmd
procesos y constantemente llenar y vaciar el búfer de canalización. Incluso si el sistemacmd
realiza1GB
grandesread()
llamadas a la vez, el control tendrá que ir y venir entrecat
ycmd
porque una tubería no puede contener más de unos pocos kilobytes de datos a la vez.cmd
s (comowc -c
) pueden hacer algunas optimizaciones cuando su stdin es un archivo normal con el que no pueden hacerlo,cat | cmd
ya que su stdin es solo una tubería. Concat
y una tubería, también significa que no puedenseek()
dentro del archivo. Para comandos comotac
otail
, eso hace una gran diferencia en el rendimiento, ya que eso significa quecat
necesitan almacenar toda la entrada en la memoria.cat $file
, e incluso su versión más correctacat -- "$file"
no funcionará correctamente para algunos nombres de archivo específicos como-
(--help
o cualquier cosa que comience-
si olvida el--
). Si uno insiste en usarlocat
, probablemente debería usarlo encat < "$file" | cmd
lugar de confiabilidad.$file
no puede abrirse para lectura (acceso denegado, no existe ...),< "$file" cmd
informará un mensaje de error coherente (por parte del shell) y no se ejecutarácmd
, mientrascat $file | cmd
que todavía se ejecutarácmd
pero con su stdin como si fuera un archivo vacío. Eso también significa que en cosas como< file cmd > file2
,file2
no se golpea sifile
no se puede abrir.fuente
truncate -s10G a; time wc -c < a; time cat a | wc -c; time cat a | cat | wc -c
. Hay muchos parámetros que entran en escena. La penalización de rendimiento puede ir de 0 a 100%. En cualquier caso, no creo que la penalización pueda ser negativa.wc -c
Es un caso bastante único, porque tiene un atajo. Si lo hace,wc -w
entonces es comparable agrep
en mi ejemplo (es decir, muy poco procesamiento, que es la situación en la que '<' puede marcar la diferencia).wc -w
en un archivo escaso de 1 GB en la configuración regional de C en linux 4.9 amd64), encuentro que el enfoque de gato tarda un 23% más de tiempo en un sistema multinúcleo y un 5% cuando los une a un núcleo. Mostrar la sobrecarga adicional incurrida al tener acceso a los datos por más de un núcleo. Posiblemente obtendrá resultados diferentes si cambia el tamaño de la tubería, usa datos diferentes, involucra E / S real, usa una implementación cat que usa empalme () ... Todo confirmando que hay muchos parámetros en la imagen y eso en cualquier casocat
no ayudará.wc -w
, es una diferencia de aproximadamente 2% ... 15% de diferencia si está en un grep simple y directo. Entonces, extrañamente, si está en un recurso compartido de archivos NFS, en realidad es un 20% más rápido leerlo si se envía desdecat
( gist.github.com/rdp/7162414833becbee5919cda855f1cb86 ) Extraño ...Poner
<file
en el extremo de una tubería es menos legible que tenercat file
al principio. El inglés natural se lee de izquierda a derecha.Diría que poner
<file
el comienzo de la tubería también es menos legible que el gato. Una palabra es más legible que un símbolo, especialmente un símbolo que parece indicar el camino equivocado.El uso
cat
conserva elcommand | command | command
formato.fuente
<
una vez hace que el código sea menos legible, ya que destruye la consistencia de sintaxis de una multiplínea.<
desea:alias load='<'
y luego utiliza por ejemploload file | sed ...
. Los alias pueden usarse en scripts después de ejecutarseshopt -s expand_aliases
.Una cosa que las otras respuestas aquí no parecen haber abordado directamente es que el uso de
cat
este tipo no es "inútil" en el sentido de que "se genera un proceso de gato extraño que no funciona"; es inútil en el sentido de que "se genera un proceso cat que solo hace un trabajo innecesario".En el caso de estos dos:
el shell inicia un proceso de sed que se lee desde algún archivo o stdin (respectivamente) y luego realiza un procesamiento: se lee hasta que llega a una nueva línea, reemplaza el primer 'foo' (si lo hay) en esa línea con 'bar', luego imprime esa línea a stdout y bucles.
En el caso de:
El caparazón genera un proceso de gato y un proceso de sed, y conecta el stdout del gato al stdin de sed. El proceso cat lee un trozo de varios kilobytes o quizás megabytes del archivo, luego lo escribe en su stdout, donde el sommand sed se recoge desde allí como en el segundo ejemplo anterior. Mientras sed está procesando ese fragmento, cat está leyendo otro fragmento y lo escribe en su stdout para que sed trabaje a continuación.
En otras palabras, el trabajo adicional necesario al agregar el
cat
comando no es solo el trabajo adicional de generar uncat
proceso adicional , sino también el trabajo adicional de leer y escribir los bytes del archivo dos veces en lugar de una vez. Ahora, prácticamente hablando y en sistemas modernos, eso no hace una gran diferencia: puede hacer que su sistema realice unos microsegundos de trabajo innecesario. Pero si se trata de un script que planea distribuir, potencialmente para las personas que lo usan en máquinas que ya tienen poca potencia, unos pocos microsegundos pueden acumularse en muchas iteraciones.fuente
cat
.cat
dividido por el ms sincat
en porcentaje (por ejemplo, 264 ms / 216 ms = 1.22 = 122% = 22% más lento concat
)