¿Por qué Shell no repara automáticamente el "uso inútil del gato"? [cerrado]

28

Muchas personas usan líneas y scripts que contienen código a lo largo de las líneas.

cat "$MYFILE" | command1 | command2 > "$OUTPUT"

El primero a catmenudo se llama "uso inútil del gato" porque técnicamente requiere comenzar un nuevo proceso (a menudo /usr/bin/cat) en el que esto podría evitarse si el comando hubiera sido

< "$MYFILE" command1 | command2 > "$OUTPUT"

porque entonces shell solo necesita comenzar command1y simplemente apuntarlo stdinal archivo dado.

¿Por qué el shell no realiza esta conversión automáticamente? Creo que la sintaxis de "uso inútil del gato" es más fácil de leer y Shell debería tener suficiente información para deshacerse del gato inútil automáticamente. El catestá definido en el estándar POSIX, por lo que se debe permitir que Shell lo implemente internamente en lugar de usar un binario en la ruta. El shell incluso podría contener la implementación solo para una versión de argumento exactamente y recurrir a la ruta binaria.

Mikko Rantalainen
fuente
22
Esos comandos no son realmente equivalentes, ya que en un caso stdin es un archivo, y en el otro es una tubería, por lo que no sería una conversión estrictamente segura. Sin embargo, podría hacer un sistema que lo hiciera.
Michael Homer
14
El hecho de que no pueda imaginar un caso de uso no significa que una aplicación no pueda confiar inútilmente en el comportamiento especificado. Obtener un error de lseektodavía es un comportamiento definido y podría causar un resultado diferente, el diferente comportamiento de bloqueo puede ser semánticamente significativo, etc. Sería posible realizar el cambio si supiera cuáles eran los otros comandos y supiera que no les importaba, o si simplemente no le importaba la compatibilidad a ese nivel, pero el beneficio es bastante pequeño. Me imagino que la falta de beneficios impulsa la situación más que el costo de conformidad.
Michael Homer
3
Sin catembargo, el shell está absolutamente autorizado a implementarse , o cualquier otra utilidad. También se permite saber cómo funcionan las otras utilidades que pertenecen al sistema (por ejemplo, puede saber cómo se comporta la grepimplementación externa que vino con el sistema ). Esto es completamente viable, por lo que es completamente justo preguntarse por qué no lo hacen.
Michael Homer
66
@MichaelHomer por ejemplo, se puede saber cómo la implementación grep exterior, que empezó con los del sistema se comporta Así que ahora la cáscara tiene una dependencia en el comportamiento de grep. Y sed. Y awk. Y du. ¿Y cuántos cientos, si no miles, de otras utilidades?
Andrew Henle
19
Sería bastante desagradable para mi shell editar mis comandos por mí.
Azor Ahai

Respuestas:

25

Los 2 comandos no son equivalentes: considere el manejo de errores:

cat <file that doesn't exist> | less producirá una secuencia vacía que se pasará al programa canalizado ... como tal, terminará con una pantalla que no muestra nada.

< <file that doesn't exist> less no podrá abrir la barra, y luego no se abrirá menos.

Intentar cambiar el primero por el último podría romper cualquier número de scripts que esperen ejecutar el programa con una entrada potencialmente en blanco.

UKMonkey
fuente
1
Marcaré su respuesta como aceptada porque creo que esta es la diferencia más importante entre ambas sintaxis. La variante con catsiempre ejecutará el segundo comando en la tubería mientras que la variante con solo la redirección de entrada no ejecutará el comando si falta el archivo de entrada.
Mikko Rantalainen
Sin embargo, tenga en cuenta que <"missing-file" grep foo | echo 2no se ejecutará, greppero se ejecutará echo.
Mikko Rantalainen
51

El "uso inútil de cat" se trata más de cómo escribe su código que de lo que realmente se ejecuta cuando ejecuta el script. Es una especie de antipatrón de diseño , una forma de hacer algo que probablemente podría hacerse de una manera más eficiente. Es un fracaso en la comprensión de cómo combinar mejor las herramientas dadas para crear una nueva herramienta. Yo diría que unir varios sedy / o awkcomandos juntos en una tubería también a veces podría decirse que es un síntoma de este mismo antipatrón.

Arreglar instancias de "uso inútil de cat" en un script es principalmente una cuestión de arreglar el código fuente del script manualmente. Una herramienta como ShellCheck puede ayudar con esto al señalar los casos obvios:

$ cat script.sh
#!/bin/sh
cat file | cat
$ shellcheck script.sh

In script.sh line 2:
cat file | cat
    ^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.

Hacer que el shell haga esto automáticamente sería difícil debido a la naturaleza de los scripts de shell. La forma en que se ejecuta un script depende del entorno heredado de su proceso padre y de la implementación específica de los comandos externos disponibles.

El caparazón no necesariamente sabe qué cates. Potencialmente podría ser cualquier comando desde cualquier parte de su $PATH, o una función.

Si se tratara de un comando incorporado (que puede estar en algunos shells), tendría la capacidad de reorganizar la canalización, ya que conocería la semántica de su catcomando incorporado . Antes de hacer eso, adicionalmente tendría que hacer suposiciones sobre el siguiente comando en la tubería, después del original cat.

Tenga en cuenta que la lectura de la entrada estándar se comporta de manera ligeramente diferente cuando está conectada a una tubería y cuando está conectada a un archivo. Una tubería no se puede buscar, por lo que, dependiendo de lo que haga el siguiente comando en la tubería, puede o no comportarse de manera diferente si la tubería se reorganizó (puede detectar si la entrada es buscable y decidir hacer las cosas de manera diferente si lo es o si no lo es, en cualquier caso, entonces se comportaría de manera diferente).

Esta pregunta es similar (en un sentido muy general) a " ¿Hay algún compilador que intente arreglar los errores de sintaxis por sí mismo? " (En el sitio de Software Engineering StackExchange), aunque esa pregunta es obviamente sobre errores de sintaxis, no patrones de diseño inútiles . Sin embargo, la idea de cambiar automáticamente el código en función de la intención es en gran medida la misma.

Kusalananda
fuente
Es perfectamente conforme para que un shell sepa qué cates, y los otros comandos en la tubería, (la regla as-if) y se comporten en consecuencia, simplemente no lo hacen aquí porque no tiene sentido y es demasiado difícil.
Michael Homer
44
@MichaelHomer Sí. Pero también está permitido sobrecargar un comando estándar con una función del mismo nombre.
Kusalananda
2
@PhilipCouling Es absolutamente conforme siempre y cuando se sepa que a ninguno de los comandos de canalización le importa. Se permite específicamente que el shell reemplace las utilidades con funciones integradas o shell y que no tienen restricciones de entorno de ejecución, por lo que siempre que el resultado externo sea indistinguible, está permitido. Para su caso, cat /dev/ttyes el interesante con el que sería diferente <.
Michael Homer
1
@MichaelHomer, por lo tanto, siempre y cuando el resultado externo sea indistinguible, está permitido. Eso significa que el comportamiento de todo el conjunto de utilidades optimizado de tal manera nunca puede cambiar . Ese tiene que ser el último infierno de dependencia.
Andrew Henle
3
@MichaelHomer Como dicen los otros comentarios, por supuesto, es perfectamente conforme para el shell saber que, dada la entrada del OP, es imposible saber qué cathace realmente el comando sin ejecutarlo . Por todo lo que (y la cáscara) conocimientos, el PO tiene un comando caten su camino, que es una simulación interactiva gato, "miarchivo" es sólo el estado del juego almacenado, y command1y command2son posprocesamiento algunas estadísticas acerca de la sesión de juego actual ...
alephzero
34

Porque no es inútil.

En el caso de cat file | cmd, el fd 0(stdin) de cmdserá una tubería, y en el caso de cmd <fileque sea un archivo, dispositivo, etc.

Una tubería tiene una semántica diferente a la de un archivo normal, y su semántica no es un subconjunto de las de un archivo normal:

  • un archivo normal no puede ser select(2)editado o poll(2)editado de manera significativa; un select(2)sobre siempre devolverá "listo". Las interfaces avanzadas como epoll(2)en Linux simplemente no funcionarán con archivos normales.

  • en Linux hay llamadas de sistema ( splice(2), vmsplice(2), tee(2)), que sólo trabajo en tuberías [1]

Como catse usa mucho, podría implementarse como un shell incorporado que evitará un proceso adicional, pero una vez que comience en ese camino, se podría hacer lo mismo con la mayoría de los comandos: transformar el shell en un proceso más lento y más complicado perlo python. Probablemente sea mejor escribir otro lenguaje de secuencias de comandos con una sintaxis similar a una tubería fácil de usar para continuar ;-)

[1] Si quieres un ejemplo simple que no esté hecho para la ocasión, puedes mirar mi git gist "exec binary from stdin" con algunas explicaciones en el comentario aquí . La implementación caten su interior para que funcione sin UUoC lo habría hecho 2 o 3 veces más grande.

Mosvy
fuente
2
De hecho, ksh93 hace poner en práctica algunos comandos externos como catinternos.
jrw32982 apoya a Monica el
3
cat /dev/urandom | cpu_bound_programejecuta las read()llamadas del sistema en un proceso separado. En Linux, por ejemplo, el trabajo real de la CPU de generar más números aleatorios (cuando el grupo está vacío) se realiza en esa llamada del sistema, por lo que usar un proceso separado le permite aprovechar un núcleo de CPU separado para generar datos aleatorios como entrada. Por ejemplo, en ¿Cuál es la forma más rápida de generar un archivo de texto de 1 GB que contenga dígitos aleatorios?
Peter Cordes
44
Más importante aún para la mayoría de los casos, significa lseekque no funcionará. cat foo.mp4 | mpv -funcionará, pero no puede buscar hacia atrás más allá del búfer de caché de mpv o mplayer. Pero con la entrada redirigida desde un archivo, puede hacerlo. cat | mpv -es una forma de verificar si un MP4 tiene su moovátomo al comienzo del archivo, para que pueda reproducirse sin buscar al final y viceversa (es decir, si es adecuado para la transmisión). Es fácil imaginar otros casos en los que desea probar un programa en busca de archivos no buscables ejecutándolo /dev/stdincon catun redireccionamiento.
Peter Cordes
Esto es aún más cierto cuando se usa xargs cat | somecmd. Si las rutas de archivo se extienden más allá del límite del búfer de comando, xargspueden ejecutarse catvarias veces, lo que resulta en una secuencia continua, mientras que el uso xargs somecmddirecto a menudo falla porque somecmdno se puede ejecutar en múltiplos para lograr un resultado perfecto.
Tasket
17

Porque detectar un gato inútil es realmente muy difícil.

Tenía un script de shell donde escribí

cat | (somecommand <<!
...
/proc/self/fd/3
...
!) 0<&3

La secuencia de comandos shell falló en la producción si el catfue eliminado porque se invoca a través su -c 'script.sh' someuser. Lo aparentemente superfluo catcausó que el propietario de la entrada estándar cambiara al usuario que el script se estaba ejecutando, de modo que su reapertura /procfuncionó.

Joshua
fuente
Este caso sería bastante fácil porque claramente no sigue el modelo simple catseguido de exactamente un parámetro, por lo que el shell debe usar un catejecutable real en lugar de un acceso directo optimizado. Sin embargo, un buen punto sobre credenciales posiblemente diferentes o stdin no estándar para procesos reales.
Mikko Rantalainen
13

tl; dr: Los depósitos no lo hacen automáticamente porque los costos exceden los beneficios probables.

Otras respuestas han señalado la diferencia técnica entre stdin ser una tubería y ser un archivo. Teniendo esto en cuenta, el shell podría hacer uno de:

  1. Implemente catcomo un archivo incorporado, conservando la distinción entre el archivo y la tubería. Esto ahorraría el costo de un ejecutivo y tal vez, posiblemente, un tenedor.
  2. Realice un análisis completo de la tubería con conocimiento de los diversos comandos utilizados para ver si el archivo / tubería es importante, luego actúe en función de eso.

A continuación, debe considerar los costos y beneficios de cada enfoque. Los beneficios son bastante simples:

  1. En cualquier caso, evite un ejecutivo (de cat)
  2. En el segundo caso, cuando es posible la sustitución de redireccionamiento, evitar una bifurcación.
  3. En los casos en que tiene que usar una tubería, a veces puede ser posible evitar una bifurcación / vfork, pero a menudo no. Esto se debe a que el equivalente de gato debe ejecutarse al mismo tiempo que el resto de la tubería.

Por lo tanto, ahorra un poco de tiempo y memoria de la CPU, especialmente si puede evitar la bifurcación. Por supuesto, solo guarda este tiempo y memoria cuando la función se usa realmente. Y realmente solo está ahorrando el tiempo fork / exec; con archivos más grandes, el tiempo es principalmente el tiempo de E / S (es decir, gato leyendo un archivo desde el disco). Entonces, debe preguntar: ¿con qué frecuencia se catusa (inútilmente) en scripts de shell donde el rendimiento realmente importa? Compárelo con otras construcciones de conchas comunes como test: es difícil imaginar que catse use (inútilmente) incluso una décima parte tan a menudo como testse usa en lugares importantes. Eso es una suposición, no lo he medido, que es algo que querría hacer antes de cualquier intento de implementación. (O de manera similar, pedirle a otra persona que implemente, por ejemplo, una solicitud de función).

A continuación, pregunta: ¿cuáles son los costos? Los dos costos que vienen a la mente son (a) código adicional en el shell, que aumenta su tamaño (y, por lo tanto, posiblemente el uso de memoria), requiere más trabajo de mantenimiento, es otro lugar para errores, etc .; y (b) sorpresas de compatibilidad con versiones anteriores, POSIX catomite muchas características de, por ejemplo, GNU coreutils cat, por lo que debe tener cuidado con exactamente lo catque implementaría el incorporado.

  1. La opción de construcción adicional probablemente no sea tan mala: agregar una construcción más donde ya exista un montón. Si tuviera datos de perfil que mostraran que ayudaría, probablemente podría convencer a los autores de su shell favorito para que lo agreguen.

  2. En cuanto al análisis de la tubería, no creo que los shells hagan algo como esto actualmente (algunos reconocen el final de una tubería y pueden evitar una bifurcación). Esencialmente, estaría agregando un optimizador (primitivo) al shell; Los optimizadores a menudo resultan ser un código complicado y la fuente de muchos errores. Y esos errores pueden ser sorprendentes: pequeños cambios en el script de shell podrían terminar evitando o activando el error.

Posdata: puede aplicar un análisis similar a sus usos inútiles de cat. Beneficios: más fácil de leer (aunque si command1 tomará un archivo como argumento, probablemente no). Costos: fork extra y exec (y si command1 puede tomar un archivo como argumento, probablemente mensajes de error más confusos). Si su análisis le dice que use gato inútilmente, continúe.

derobert
fuente
10

El catcomando puede aceptar -como marcador para stdin . ( POSIX , " Si un archivo es '-', la utilidad cat leerá de la entrada estándar en ese punto de la secuencia "). Esto permite el manejo simple de un archivo o stdin donde, de lo contrario, esto no se permitiría.

Considere estas dos alternativas triviales, donde el argumento de shell $1es -:

cat "$1" | nl    # Works completely transparently
nl < "$1"        # Fails with 'bash: -: No such file or directory'

Otro momento catútil es cuando se usa intencionalmente como un no-op simplemente para mantener la sintaxis de shell:

file="$1"
reader=cat
[[ $file =~ \.gz$ ]] && reader=zcat
[[ $file =~ \.bz2$ ]] && reader=bzcat
"$reader" "$file"

Finalmente, creo que el único momento en que realmente se puede invocar correctamente UUOC es cuando catse usa con un nombre de archivo que se sabe que es un archivo normal (es decir, no un dispositivo o canalización con nombre), y que no se dan banderas al comando:

cat file.txt

En cualquier otra situación, las oroperties de catsí mismo pueden ser necesarias.

roaima
fuente
6

El comando cat puede hacer cosas que el shell no necesariamente puede hacer (o al menos, no puede hacer fácilmente). Por ejemplo, suponga que desea imprimir caracteres que de otro modo serían invisibles, como pestañas, retornos de carro o líneas nuevas. * Podría * haber una manera de hacerlo con solo comandos integrados de shell, pero no puedo pensar en ninguno fuera de mi cabeza. La versión GNU de cat puede hacerlo con el -Aargumento o los -v -E -Targumentos (aunque no sé sobre otras versiones de cat). También puede prefijar cada línea con un número de línea usando -n(nuevamente, IDK si las versiones que no son GNU pueden hacer esto).

Otra ventaja de cat es que puede leer fácilmente múltiples archivos. Para hacerlo, uno simplemente puede escribir cat file1 file2 file3. Para hacer lo mismo con un shell, las cosas se pondrían difíciles, aunque un ciclo cuidadosamente diseñado probablemente podría lograr el mismo resultado. Dicho esto, ¿realmente quieres tomarte el tiempo de escribir un ciclo así, cuando existe una alternativa tan simple? ¡Yo no!

Leer archivos con cat probablemente usaría menos CPU que el shell, ya que cat es un programa precompilado (la excepción obvia es cualquier shell que tenga un gato incorporado). Al leer un gran grupo de archivos, esto puede ser evidente, pero nunca lo he hecho en mis máquinas, por lo que no puedo estar seguro.

El comando cat también puede ser útil para forzar a un comando a aceptar entradas estándar en casos en los que no lo haga. Considera lo siguiente:

echo 8 | sleep

El comando "sleep" no aceptará el número "8", ya que nunca tuvo la intención de aceptar una entrada estándar. Por lo tanto, el sueño no tendrá en cuenta esa entrada, se quejará de la falta de argumentos y saldrá. Sin embargo, si uno escribe:

echo 8 | sleep $(cat)

Muchos proyectiles expandirán esto sleep 8y el sueño esperará 8 segundos antes de salir. También puedes hacer algo similar con ssh:

command | ssh 1.2.3.4 'cat >> example-file'

Este comando con un archivo de ejemplo adjunto en la máquina con la dirección de 1.2.3.4 con lo que salga del "comando".

Y eso (probablemente) solo está rascando la superficie. Estoy seguro de que podría encontrar más ejemplos de gatos útiles si quisiera, pero esta publicación es lo suficientemente larga como es. Entonces, concluiré diciendo esto: pedirle al shell que anticipe todos estos escenarios (y varios otros) no es realmente factible.

TSJNachos117
fuente
Terminaría la última oración con "no es fácilmente factible"
Basile Starynkevitch
3

Recuerde que un usuario podría tener un caten su $PATHque no es exactamente el POSIX cat(pero quizás alguna variante que podría registrar algo en alguna parte). En ese caso, no desea que el shell lo elimine.

El PATH podría cambiar dinámicamente, y entonces cat no es lo que crees que es. Sería bastante difícil escribir un shell haciendo la optimización que sueñas.

Además, en la práctica, cat es un programa bastante rápido. Hay pocas razones prácticas (excepto la estética) para evitarlo.

Vea también la excelente charla del infierno Parsing POSIX [s] de Yann Regis-Gianas en FOSDEM2018. Proporciona otras buenas razones para evitar intentar hacer lo que sueñas en una concha.

Si el rendimiento fuera realmente un problema para los shells, alguien habría propuesto un shell que utiliza una sofisticada optimización del compilador de todo el programa, análisis de código fuente estático y técnicas de compilación justo a tiempo (estos tres dominios tienen décadas de progreso y publicaciones científicas y dedicadas conferencias, por ejemplo, bajo SIGPLAN ). Lamentablemente, incluso como un tema de investigación interesante, que actualmente no está financiado por agencias de investigación o capitalistas de riesgo, y deduzco que simplemente no vale la pena el esfuerzo. En otras palabras, probablemente no haya un mercado significativo para optimizar los depósitos . Si tiene medio millón de euros para gastar en dicha investigación, encontrará fácilmente a alguien que lo haga, y creo que daría resultados valiosos.

Desde un punto de vista práctico, la reescritura, para mejorar su rendimiento, se hace comúnmente un pequeño script de shell (un centenar de líneas) en cualquier lenguaje de script mejor (Python, AWK, Guile, ...). Y no es razonable (por muchas razones de ingeniería de software) escribir scripts de shell grandes: cuando está escribiendo un script de shell que supera las cien líneas, debe considerar reescribirlo (incluso por razones de legibilidad y mantenimiento) en un lenguaje más adecuado : como lenguaje de programación, el shell es muy pobre. Sin embargo, hay muchos scripts de shell generados de gran tamaño , y por buenas razones (por ejemplo, configurescripts generados de autoconfiguración de GNU ).

Con respecto a los archivos de texto enormes, pasarlos catcomo un solo argumento no es una buena práctica, y la mayoría de los administradores de sistemas lo saben (cuando cualquier script de shell tarda más de un minuto en ejecutarse, comienza a considerar la optimización). Para archivos de gigabytes grandes, nuncacat es la buena herramienta para procesarlos.

Basile Starynkevitch
fuente
3
"Muy pocas razones prácticas para evitarlo": cualquier persona que haya esperado cat some-huge-log | tail -n 5correr (donde tail -n 5 some-huge-logpodría saltar directamente al final, mientras que catsolo lee de adelante hacia atrás) no estaría de acuerdo.
Charles Duffy
El comentario desprotege ^ catun archivo de texto grande en un rango de decenas de GB (que fue creado para probar) lleva un poco más de tiempo. No lo recomendaría
Sergiy Kolodyazhnyy
1
Por cierto, re: "no hay un mercado significativo para optimizar los shells": ksh93 es un shell optimizador y bastante bueno. Se fue , por un tiempo, vendió con éxito como un producto comercial. (Lamentablemente, tener una licencia comercial también lo hizo lo suficientemente nicho como para que los clones mal escritos y otros sucesores menos capaces pero sin costo se hicieran cargo del mundo fuera de esos sitios dispuestos a pagar por una licencia, lo que lleva a la situación que nosotros tener hoy).
Charles Duffy
(no utiliza las técnicas específicas que observa, pero, francamente, esas técnicas no tienen sentido dado el modelo de proceso; las técnicas que aplica son, bien, bien aplicadas y con buenos resultados ).
Charles Duffy
2

Agregando a la respuesta de @Kusalananda (y el comentario de @alephzero), cat podría ser cualquier cosa:

alias cat='gcc -c'
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

o

echo 'echo 1' > /usr/bin/cat
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

No hay ninguna razón para que cat (solo) o / usr / bin / cat en el sistema sea realmente la herramienta concatenada cat.

Robar
fuente
3
Además del comportamiento de, catestá definido por POSIX, por lo que no debería ser muy diferente.
Roaima
2
@roaima: PATH=/home/Joshua/bin:$PATH cat ...¿Estás seguro de que sabes lo que cathace ahora?
Joshua
1
@Joshua realmente no importa. Ambos sabemos que catse puede anular, pero también sabemos que no debería reemplazarse sin motivo por algo más. Mi comentario señala que POSIX exige un comportamiento particular (subconjunto de) que razonablemente puede esperarse que exista. A veces, he escrito un script de shell que extiende el comportamiento de una utilidad estándar. En este caso, el script de shell actuó y se comportó como la herramienta que reemplazó, excepto que tenía capacidades adicionales.
Roaima
@Joshua: en la mayoría de las plataformas, los shells saben (o podrían saber) qué directorios contienen ejecutables que implementan comandos POSIX. Por lo tanto, podría diferir la sustitución hasta después de la expansión del alias y la resolución de la ruta, y solo hacerlo por /bin/cat. (Y lo convertiría en una opción que podría desactivar). O crearía catun shell incorporado (¿que quizás recurra a /bin/catmúltiples argumentos?) Para que los usuarios puedan controlar si querían o no la versión externa normal camino, con enable cat. Me gusta para kill. (Estaba pensando que bash command catfuncionaría, pero eso no se salta los builtins)
Peter Cordes
Si proporciona un alias, el shell sabrá que caten ese entorno ya no se refiere a lo habitual cat. Obviamente, la optimización debe implementarse después de que se hayan procesado los alias. Considero que los complementos de shell representan comandos en el directorio virtual que siempre se antepone a su ruta. Si desea evitar la versión integrada de shell de cualquier comando (por ejemplo test), debe usar una variante con una ruta.
Mikko Rantalainen
1

Dos usos "inútiles" para el gato:

sort file.txt | cat header.txt - footer.txt | less

... aquí catse usa para mezclar archivos y entradas canalizadas.

find . -name '*.info' -type f | sh -c 'xargs cat' | sort

... aquí xargspuede aceptar un número virtualmente infinito de nombres de archivo y ejecutarse cattantas veces como sea necesario mientras hace que todo se comporte como una secuencia. Por lo tanto, esto funciona para listas de archivos grandes donde el uso directo de xargs sortno lo hace.

tasket
fuente
Ambos casos de uso se evitarían trivialmente haciendo que el intérprete de comandos integrado solo intervenga si catse llama con exactamente un argumento. Especialmente en el caso en que shse pasa una cadena y xargsllamará catdirectamente, no hay forma de que el shell pueda usar su implementación incorporada.
Mikko Rantalainen
0

Además de otras cosas, cat-check agregaría sobrecarga de rendimiento adicional y confusión sobre qué uso de cates realmente inútil, en mi humilde opinión, porque tales comprobaciones pueden ser ineficientes y crear problemas con el catuso legítimo .

Cuando los comandos tratan con las secuencias estándar, solo tienen que preocuparse por leer / escribir en los descriptores de archivo estándar. Los comandos pueden saber si stdin se puede buscar / buscar o no, lo que indica una tubería o un archivo.

Si agregamos a la mezcla comprobando qué proceso realmente proporciona ese contenido estándar, necesitaremos encontrar el proceso al otro lado de la tubería y aplicar la optimización adecuada. Esto se puede hacer en términos de shell en sí, como se muestra en la publicación SuperUser de Kyle Jones, y en términos de shell que es

(find /proc -type l | xargs ls -l | fgrep 'pipe:[20043922]') 2>/dev/null

como se muestra en la publicación vinculada. Estos son 3 comandos más (tan fork()s y exec()s extra ) y recorridos recursivos (muchas readdir()llamadas).

En términos de C y el código fuente del shell, el shell ya conoce el proceso secundario, por lo que no hay necesidad de recurrencia, pero ¿cómo sabemos cuándo optimizar y cuándo cates realmente inútil? De hecho, hay usos útiles del gato , como

# adding header and footer to file
( cmd; cat file; cmd ) | cmd
# tr command does not accept files as arguments
cat log1 log2 log3 | tr '[:upper:]' '[:lower:]'

Probablemente sería un desperdicio y una sobrecarga innecesaria agregar tal optimización al shell. Como ya mencionó la respuesta de Kusalanda, UUOC trata más sobre la falta de comprensión del usuario sobre cómo combinar mejor los comandos para obtener los mejores resultados.

Sergiy Kolodyazhnyy
fuente