¿Cómo puedo ejecutar dos comandos en una entrada, sin escribir esa entrada dos veces?
Por ejemplo, el comando stat dice mucho sobre un archivo, pero no indica su tipo de archivo:
stat fileName
El comando de archivo, dice de qué tipo es un archivo:
file fileName
Puede realizar esto en una línea de esta manera:
stat fileName ; file fileName
Sin embargo, debe escribir el nombre de archivo dos veces.
¿Cómo puede ejecutar ambos comandos en la misma entrada (sin escribir la entrada o una variable de la entrada dos veces)?
En Linux, sé cómo canalizar salidas, pero ¿cómo canalizas las entradas?
command-line
Lonniebiz
fuente
fuente
<
(entrada del archivo al lado izquierdo) o|
(entrada del flujo al lado derecho). Hay una diferenciayank-last-arg
comando (atajo predeterminadoMeta-.
oMeta-_
; aMeta
menudo es laAlt
tecla izquierda ) copiará el último parámetro de la línea de comando anterior en el actual. Entonces, después de ejecutarstat fileName
, escribefile [Meta-.]
y no tiene quefileName
volver a escribir eso . Yo siempre uso eso.<
y>
son redireccionamientos , no tuberías . Una tubería conecta dos procesos, mientras que la redirección simplemente reasigna stdin / stdout.Respuestas:
Aquí hay otra forma:
Ejemplo:
Eso funciona en
bash
yzsh
. Eso también funcionamksh
ydash
solo cuando es interactivo. En AT&T ksh, eso solo funciona cuandofile "$_"
está en una línea diferente de la questat
está.fuente
!$
uno no funcionará porque se!$
expande hasta la última palabra del último evento del historial (por lo tanto, de la línea de comando ingresada anteriormente, no del comando stat).Probablemente voy a hacer que me golpeen los nudillos por esto, aquí hay una combinación hacky de expansión de brazalete bash y evaluación que parece hacer el truco
fuente
csh
, nobash
.bash
copiaste desdeksh
. Ese código funcionará en todos los csh, tcsh, ksh, zsh, fish y bash.eval
? (refiriéndose a los comentarios principales)Con
zsh
, puedes usar funciones anónimas:Con
es
lambdas:También puedes hacer:
(haciendo lo
stat
primero yafile
que actualizará el tiempo de acceso).Lo haría:
sin embargo, para eso están las variables.
fuente
{ stat -; file -;} < filename
es mágico.stat
debe verificar para ver si su stdin está conectado a un archivo e informar los atributos del archivo? Presumiblemente no avanza el puntero en stdin, por lo tanto, permitefile
oler el contenido de stdinstat -
dicestat
que hacer unafstat()
en su fd 0.{ $COMMAND_A -; $COMMAND_B; } < filename
variante no funcionará en el caso general si $ COMMAND_A realmente lee alguna entrada; Por ejemplo{ cat -; cat -; } < filename
, imprimirá el contenido del nombre de archivo solo una vez.stat -
se maneja especialmente desde coreutils-8.0 (octubre de 2009), en versiones anteriores obtendrá un error (a menos que haya llamado un archivo-
de un experimento anterior, en cuyo caso obtendrá los resultados incorrectos ...)stat -f0
en su lugar.Todas estas respuestas me parecen scripts, en mayor o menor medida. Para una solución que realmente no implique secuencias de comandos y suponga que está sentado en el teclado escribiendo en un shell, puede intentar:
Al menos en bash, zsh y ksh, en los modos vi y emacs, al presionar Escape y luego subrayar se inserta la última palabra de la línea anterior en el búfer de edición para la línea actual.
O puede usar la sustitución del historial:
En bash, zsh, csh, tcsh y la mayoría de los shells,
!$
se reemplaza con la última palabra de la línea de comando anterior cuando se analiza la línea de comando actual.fuente
Esc _
? ¿Pueden enlazar con la documentación oficial?La forma en que he encontrado para hacer esto razonablemente simplemente es usando xargs, toma un archivo / tubería y convierte su contenido en argumentos de programa. Esto se puede combinar con tee que divide una secuencia y la envía a dos o más programas. En su caso, necesita:
A diferencia de muchas de las otras respuestas, esto funcionará en bash y en la mayoría de los shells en Linux. Sugeriré que este es un buen caso de uso de una variable, pero si no puede usar una, esta es la mejor manera de hacerlo solo con tuberías y utilidades simples (suponiendo que no tenga un shell particularmente elegante).
Además, puede hacer esto para cualquier número de programas simplemente agregándolos de la misma manera que estos dos después del tee.
EDITAR
Como se sugiere en los comentarios, hay un par de fallas en esta respuesta, la primera es el potencial para el entrelazado de salida. Esto se puede solucionar así:
Esto obligará a los comandos a ejecutarse a su vez y la salida nunca se entrelazará.
El segundo problema es evitar la sustitución del proceso que no está disponible en algunos shells, esto se puede lograr usando tpipe en lugar de tee como sigue:
Esto debería ser portátil para casi cualquier shell (espero) y resuelve los problemas en el otro comentario, sin embargo, estoy escribiendo este último de memoria ya que mi sistema actual no tiene tpipe disponible.
fuente
ksh
(no las variantes de dominio público)bash
yzsh
. Tenga en cuenta questat
yfile
se ejecutará simultáneamente, por lo que posiblemente su salida se entrelazará (¿supongo que está utilizando| cat
para forzar el almacenamiento en búfer de salida para limitar ese efecto?).Esta respuesta es similar a algunas de las otras:
A diferencia de las otras respuestas, que repiten automáticamente el último argumento del comando anterior, este requiere que cuentes:
A diferencia de algunas de las otras respuestas, esto no requiere comillas:
o
fuente
Esto es similar a algunas de las otras respuestas, pero es más portátil que esta y mucho más simple que esta :
o
en el que
sh
está asignado$0
. Aunque son tres caracteres más para escribir, esta (segunda) forma es preferible porque ese$0
es el nombre que le da a esa secuencia de comandos en línea. Se utiliza, por ejemplo, en los mensajes de error por la cáscara de ese guión, como cuandofile
ostat
no se puede encontrar o no puede ser ejecutado por cualquier motivo.Si quieres hacer
para un número arbitrario de archivos, hacer
que funciona porque
"$@"
es equivalente a"$1" "$2" "$3" …
.fuente
$0
es el nombre que desea darle a ese script en línea. Se usa, por ejemplo, en mensajes de error del shell para ese script. Como cuandofile
ostat
no se puede encontrar o no puede ser ejecutado por cualquier motivo. Entonces, quieres algo significativo aquí. Si no está inspirado, solo úselosh
.Creo que está haciendo una pregunta incorrecta, al menos por lo que está tratando de hacer.
stat
y losfile
comandos toman parámetros que son el nombre de un archivo y no el contenido del mismo. Es más tarde en el comando que hace la lectura del archivo identificado por el nombre que está especificando.Se supone que una tubería tiene dos extremos, uno utilizado como entrada y otro como salida, y esto tiene sentido, ya que es posible que deba realizar un procesamiento diferente en el camino con diferentes herramientas hasta obtener el resultado necesario. Decir que sabe cómo canalizar salidas pero no sabe cómo canalizar entradas no es correcto en principio.
En su caso, no necesita una tubería, ya que debe proporcionar la entrada en forma de nombre de archivo. E incluso si esas herramientas (
stat
yfile
) leyeran stdin, la tubería no es relevante aquí nuevamente ya que ninguna de las herramientas debería alterar la entrada cuando llegue a la segunda.fuente
Esto debería funcionar para todos los nombres de archivo en el directorio actual.
fuente
}
... caracteres y no comience con-
. Algunasprintf
implementaciones (zsh, bash, ksh93) tienen a%q
. Conzsh
, eso podría ser:printf 'stat %q; file %1$q\n' ./* | zsh
sed
s///
, pero se trata de alcance, y si las personas lo ponen en sus nombres de archivo, deberían usar Windows.*
dos veces . También podrías decirlostat -- *; file -- *
.*
se expande. La expansión de*
más los dos comandos para cada argumento en*
es la entrada. ¿Ver?printf commands\ %s\;shift *
Aquí hay algunas referencias diferentes a 'entrada', por lo que daré algunos escenarios teniendo en cuenta primero. Para su respuesta rápida a la pregunta en forma más corta :
Lo anterior realizará una estadística en el archivo de prueba, tomará (redirigirá) su STDOUT e incluirá eso en la siguiente función especial (la parte <()) y luego generará los resultados finales de lo que sea, en un nuevo archivo (archivo de salida). Se llama al archivo, luego se hace referencia a él con bash incorporado ($ 1 cada vez, hasta que comience un nuevo conjunto de instrucciones).
Su pregunta es excelente, y hay varias respuestas y formas de hacerlo, pero de hecho cambia con lo que está haciendo específicamente.
Por ejemplo, también puedes repetir eso, lo cual es bastante útil. Un uso común de esto es, en la mentalidad de código psuedo, es:
Tomar eso y expandir ese conocimiento le permite crear cosas como:
Esto realizará un simple ls -A en su directorio actual, luego le dirá al tiempo que recorra cada resultado desde el ls -A a (¡y aquí es difícil!) Grep "esa palabra" en cada uno de esos resultados, y solo realice el anterior printf (en rojo) si realmente encontró un archivo con "esa palabra" en él. También registrará los resultados del grep en un nuevo archivo de texto, files_that_matched_thatword.
Salida de ejemplo:
Todo eso simplemente imprimió el resultado ls -A, nada especial. Agregue algo para que grep esta vez:
Ahora vuelva a ejecutarlo:
Aunque tal vez sea una respuesta más agotadora de la que está buscando en la actualidad, creo que mantener notas útiles como esta le beneficiará mucho más en futuros esfuerzos.
fuente