Saltar al contenido

¿Cuáles son los operadores de redireccionamiento y control del shell?

Solución:

Estos se llaman operadores de shell y sí, hay más de ellos. Daré una breve descripción de los más comunes entre las dos clases principales, los operadores de control y los operadores de redirección, y cómo funcionan con respecto al shell bash.

A. Operadores de control

Definición de POSIX

En el lenguaje de comandos de shell, un token que realiza una función de control.
Es uno de los siguientes símbolos:

&   &&   (   )   ;   ;;      |   ||

Y |& en bash.

A ! es no un operador de control pero una palabra reservada. Se convierte en un NO lógico [negation operator] dentro de Expresiones aritméticas y construcciones de prueba internas (aunque todavía requiere un delimitador de espacio).

A.1 Lista de terminadores

  • ; : Ejecutará un comando después de que otro haya terminado, independientemente del resultado del primero.

    command1 ; command2
    

    Primero command1 se ejecuta, en primer plano, y una vez finalizado, command2 se ejecutará.

    Una nueva línea que no está en un literal de cadena o después de ciertas palabras clave es no equivalente al operador de punto y coma. Una lista de ; comandos simples delimitados sigue siendo un lista – como en el analizador de shell, aún debe continuar leyendo en los comandos simples que siguen a un ; comando simple delimitado antes de ejecutarlo, mientras que una nueva línea puede delimitar una lista completa de comandos, o una lista de listas. La diferencia es sutil, pero complicada: dado que el shell no tiene un imperativo previo para leer datos después de una nueva línea, la nueva línea marca un punto en el que el shell puede comenzar a evaluar los comandos simples que ya ha leído, mientras que un ; el punto y coma no lo hace.

  • & : Esto ejecutará un comando en segundo plano, lo que le permitirá continuar trabajando en el mismo shell.

     command1 & command2
    

    Aquí, command1 se inicia en segundo plano y command2 comienza a correr en primer plano inmediatamente, sin esperar command1 salir.

    Una nueva línea después command1 es opcional.

A.2 Operadores lógicos

  • && : Se utiliza para crear listas Y, le permite ejecutar un comando solo si otro salió con éxito.

     command1 && command2
    

    Aquí, command2 correrá después command1 ha terminado y solamente si command1 tuvo éxito (si su código de salida era 0). Ambos comandos se ejecutan en primer plano.

    Este comando también se puede escribir

    if command1
    then command2
    else false
    fi
    

    o simplemente if command1; then command2; fi si se ignora el estado de devolución.

  • || : Se utiliza para crear listas OR, le permite ejecutar un comando solo si otro salió sin éxito.

     command1 || command2
    

    Aquí, command2 solo se ejecutará si command1 falló (si devolvió un estado de salida distinto de 0). Ambos comandos se ejecutan en primer plano.

    Este comando también se puede escribir

    if command1
    then true
    else command2
    fi
    

    o de una manera más corta if ! command1; then command2; fi.

    Tenga en cuenta que && y || son asociativos por la izquierda; ver Prioridad de los operadores lógicos de shell &&, || para más información.

  • !: Esta es una palabra reservada que actúa como el operador “no” (pero debe tener un delimitador), que se utiliza para negar el estado de retorno de un comando; devuelve 0 si el comando devuelve un estado distinto de cero, devuelve 1 si devuelve el estado 0 . También un NO lógico para el test utilidad.

    ! command1
    
    [ ! a = a ]
    

    Y un verdadero operador NOT dentro de Expresiones aritméticas:

    $ echo $((!0)) $((!23))
    1 0
    

A.3 Operador de tubería

  • | : El operador de tubería, pasa la salida de un comando como entrada a otro. Un comando creado a partir del operador de tubería se denomina tubería.

     command1 | command2
    

    Cualquier salida impresa por command1 se pasa como entrada a command2.

  • |& : Esta es una abreviatura de 2>&1 | en bash y zsh. Pasa tanto la salida estándar como el error estándar de un comando como entrada a otro.

    command1 |& command2
    

A.4 Otra puntuación de la lista

;; se utiliza únicamente para marcar el final de una declaración de caso. Ksh, bash y zsh también son compatibles ;& pasar al siguiente caso y ;;& (no en ATT ksh) para continuar y probar los casos posteriores.

( y ) se utilizan para agrupar comandos y ejecutarlos en una subcapa. y también grupos de comandos, pero no los inicie en un subshell. Vea esta respuesta para una discusión de los diversos tipos de paréntesis, corchetes y llaves en la sintaxis de shell.

B. Operadores de redireccionamiento

Definición de POSIX de operador de redirección

En el lenguaje de comandos de shell, un token que realiza una función de redirección. Es uno de los siguientes símbolos:

<     >     >|     <<     >>     <&     >&     <<-     <>

Estos le permiten controlar la entrada y salida de sus comandos. Pueden aparecer en cualquier lugar dentro de un comando simple o pueden seguir un comando. Las redirecciones se procesan en el orden en que aparecen, de izquierda a derecha.

  • < : Da entrada a un comando.

    command < file.txt
    

    Lo anterior se ejecutará command sobre el contenido de file.txt.

  • <> : igual que arriba, pero el archivo está abierto en leer + escribir modo en lugar de solo lectura:

    command <> file.txt
    

    Si el archivo no existe, se creará.

    Ese operador rara vez se usa porque los comandos generalmente solo leer de su stdin, aunque puede resultar útil en una serie de situaciones específicas.

  • > : Dirige la salida de un comando a un archivo.

    command > out.txt
    

    Lo anterior guardará la salida de command como out.txt. Si el archivo existe, se sobrescribirá su contenido y si no existe se creará.

    Este operador también se usa a menudo para elegir si algo debe imprimirse con un error estándar o una salida estándar:

    command >out.txt 2>error.txt
    

    En el ejemplo anterior, > redirigirá la salida estándar y 2> redirecciona el error estándar. La salida también se puede redirigir usando 1> pero, dado que este es el valor predeterminado, 1 generalmente se omite y se escribe simplemente como >.

    Entonces, para correr command sobre file.txt y guarde su salida en out.txt y cualquier mensaje de error en error.txt correría:

    command < file.txt > out.txt 2> error.txt
    
  • >| : Hace lo mismo que >, pero sobrescribirá el destino, incluso si el shell se ha configurado para rechazar la sobrescritura (con set -C o set -o noclobber).

    command >| out.txt
    

    Si out.txt existe, la salida de command reemplazará su contenido. Si no existe, se creará.

  • >> : Hace lo mismo que >, excepto que si el archivo de destino existe, se añaden los nuevos datos.

    command >> out.txt
    

    Si out.txt existe, la salida de command se agregará a él, después de lo que ya esté en él. Si no existe, se creará.

  • >& : (según la especificación POSIX) cuando está rodeado por digitos (1>&2) o - en el lado derecho (1>&-) ya sea solo redirecciona uno descriptor de archivo o lo cierra (>&-).

    A >& seguido de un número de descriptor de archivo es una forma portátil de redirigir un descriptor de archivo, y >&- es una forma portátil de cerrar un descriptor de archivo.

    Si el lado derecho de esta redirección es un archivo, lea la siguiente entrada.

  • >&, &>, >>& y &>> : (lea también arriba) Redirigir tanto el error estándar como la salida estándar, reemplazando o agregando, respectivamente.

    command &> out.txt
    

    Tanto el error estándar como la salida estándar de command será guardado en out.txt, sobrescribiendo su contenido o creándolo si no existe.

    command &>> out.txt
    

    Como arriba, excepto que si out.txt existe, la salida y el error de command se le agregará.

    los &> variante se origina en bash, mientras que la >& La variante proviene de csh (décadas antes). Ambos entran en conflicto con otros operadores de shell POSIX y no deben usarse en dispositivos portátiles. sh guiones.

  • << : Un documento aquí. A menudo se utiliza para imprimir cadenas de varias líneas.

     command << WORD
         Text
     WORD
    

    Aquí, command tomará todo hasta que encuentre la próxima aparición de WORD, Text en el ejemplo anterior, como entrada. Tiempo WORD es seguido EoF o variaciones de los mismos, puede ser cualquier cadena alfanumérica (y no solo) que desee. Cuando WORD se cita, el texto del documento aquí se trata literalmente y no se realizan ampliaciones (en variables, por ejemplo). Si no está entre comillas, las variables se expandirán. Para obtener más detalles, consulte el manual de bash.

    Si desea canalizar la salida de command << WORD ... WORD directamente en otro comando o comandos, debe poner la tubería en la misma línea que << WORD, no puede ponerlo después de la PALABRA de terminación o en la línea siguiente. Por ejemplo:

     command << WORD | command2 | command3...
         Text
     WORD
    
  • <<< : Aquí cadenas, similares a aquí documentos, pero destinadas a una sola línea. Estos existen solo en el puerto Unix o rc (donde se originó), zsh, algunas implementaciones de ksh, yash y bash.

    command <<< WORD
    

    Todo lo que se da como WORD se expande y su valor se pasa como entrada a command. Esto se usa a menudo para pasar el contenido de las variables como entrada a un comando. Por ejemplo:

     $ foo="bar"
     $ sed 's/a/A/' <<< "$foo"
     bAr
     # as a short-cut for the standard:
     $ printf '%sn' "$foo" | sed 's/a/A/'
     bAr
     # or
     sed 's/a/A/' << EOF
     $foo
     EOF
    

Algunos otros operadores (>&-, x>&yx<&y) se puede utilizar para cerrar o duplicar descriptores de archivos. Para obtener detalles sobre ellos, consulte la sección correspondiente del manual de su shell (aquí, por ejemplo, para bash).

Eso solo cubre los operadores más comunes de conchas tipo Bourne. Algunos shells tienen algunos operadores de redirección adicionales propios.

Ksh, bash y zsh también tienen construcciones <(…), >(…) y =(…) (ese último en zsh solamente). No se trata de redirecciones, sino de sustitución de procesos.

Advertencia sobre '>'

Los principiantes de Unix que acaban de aprender sobre la redirección de E / S (< y >) a menudo intenta cosas como

commandinput_file > the_same_file

o

command … < file     > the_same_file

o, casi de manera equivalente,

cat file | command … > the_same_file

(grep, sed, cut, sort, y spell son ejemplos de comandos que la gente se siente tentada a usar en construcciones como estas). Los usuarios se sorprenden al descubrir que estos escenarios dan como resultado que el archivo se vacíe.

Un matiz que no parece mencionarse en la otra respuesta se puede encontrar acechando en la primera oración de la Redirección sección de bash (1):

Antes de que se ejecute un comando, su entrada y salida pueden ser redirigido
utilizando una notación especial interpretada por el shell.

Las primeras cinco palabras deben estar en negrita, cursiva, subrayadas, ampliadas, parpadeando, coloreadas en rojo y marcadas con un signo de exclamación en triángulo rojo

icono, a enfatizar el hecho de que el shell realiza las redirecciones solicitadas
antes de que se ejecute el comando. Y recuerda tambien

La redirección de la salida hace que el archivo… se abra para escritura…. Si el archivo no existe, se crea; si existe, se trunca a tamaño cero.

  1. Entonces, en este ejemplo:

    sort roster > roster
    

    el caparazón abre el roster archivo para escribir, truncándolo (es decir, descartando todo su contenido), antes de la sort el programa comienza a ejecutarse. Naturalmente, no se puede hacer nada para recuperar los datos.

  2. Uno podría esperar ingenuamente que

    tr "[:upper:]" "[:lower:]" < poem > poem
    

    podría ser mejor. Debido a que el shell maneja las redirecciones de izquierda a derecha, se abre poem para leer (para trentrada estándar) antes de que se abra para escribir (para salida estándar). Pero eso no ayuda. Aunque esta secuencia de operaciones produce dos identificadores de archivo, ambos apuntan al mismo archivo. Cuando el shell abre el archivo para su lectura, el contenido todavía está allí, pero todavía se golpea antes de que se ejecute el programa.

Entonces, ¿qué hacer al respecto?

Las soluciones incluyen:

  • Compruebe si el programa que está ejecutando tiene su propia capacidad interna para especificar a dónde va la salida. Esto a menudo se indica mediante un -o (o --output=) token. En particular,

    sort -o roster roster
    

    es aproximadamente equivalente a

    sort roster > roster
    

    excepto, en el primer caso, el sort programa abre el archivo de salida. Y es lo suficientemente inteligente como para no abrir el archivo de salida hasta después ha leído todos los archivos de entrada.

    Del mismo modo, al menos algunas versiones de sed tener un -i (editar In lugar) opción que se puede utilizar para volver a escribir la salida en el archivo de entrada (de nuevo, después se han leído todas las entradas). A los editores les gusta ed/ex, emacs, pico, y vi/vim
    Permitir al usuario editar un archivo de texto y guardar el texto editado en el archivo original. Tenga en cuenta que ed (al menos) se puede utilizar de forma no interactiva.

    • vi tiene una característica relacionada. Si escribe :%!commandIngresar, escribirá el contenido del búfer de edición en command, lea la salida e insértela en el búfer (reemplazando el contenido original).
  • Simple pero efectivo:

    commandinput_file > temp_file  &&  mv temp_fileinput_file

    Esto tiene el inconveniente de que, si input_file es un enlace, (probablemente) será reemplazado por un archivo separado. Además, el nuevo archivo será de su propiedad, con protecciones predeterminadas. En particular, esto conlleva el riesgo de que el archivo termine siendo legible por todo el mundo, incluso si el original input_file no lo era.

    Variaciones:

    • commandinput_file > temp_file && cp temp_fileinput_file && rm temp_file

      que todavía (potencialmente) dejará el temp_file legible en todo el mundo. Aun mejor:

    • cp input_filetemp_file && commandtemp_file > input_file && rm temp_file

      Estos conservan el estado del enlace, el propietario y el modo (protección) del archivo, potencialmente a costa del doble de E / S. (Es posible que deba utilizar una opción como -a o -p sobre cp
      para decirle que conserve los atributos).

    • commandinput_file > temp_file &&
      cp --attributes-only --preserve=all input_filetemp_file &&
      mv temp_fileinput_file

      (dividido en líneas separadas solo para facilitar la lectura) Esto conserva el modo del archivo (y, si es root, el propietario), pero lo convierte en propiedad suya (si no es root), y lo convierte en un nuevo, archivo separado.

  • Este blog (edición de archivos "in situ") sugiere y explica

     rm input_file  &&  command … > input_file;  < input_file

    Esto requiere que el command Ser capaz de procesar la entrada estándar (pero casi todos los filtros pueden). El blog en sí mismo llama a esto una tontería arriesgada y desaconseja su uso. Y esto también creará un nuevo archivo separado (no vinculado a nada), de su propiedad y con permisos predeterminados.

  • El paquete moreutils tiene un comando llamado sponge:

    commandinput_file | sponge the_same_file

    Consulte esta respuesta para obtener más información.

Aquí hay algo que me sorprendió por completo: error de sintaxis dice:

[Most of these solutions] fallará en un sistema de archivos de solo lectura, donde "solo lectura" significa que su $HOMEvoluntad ser escribible, pero /tmp estarán solo lectura (por defecto). Por ejemplo, si tiene Ubuntu y ha iniciado en la Consola de recuperación, este suele ser el caso. Además, el operador here-document <<< tampoco funcionará allí, ya que requiere /tmp ser leer escribir
porque también escribirá un archivo temporal allí.
(cf. esta pregunta incluye un strace'd salida)

Lo siguiente puede funcionar en ese caso:

  • Solo para usuarios avanzados:
    Si se garantiza que su comando producirá la misma cantidad de datos de salida que de entrada (por ejemplo, sort, o trsin los -d o -s opción), puedes probar

    commandinput_file | dd of=the_same_file conv=notrunc

    Consulte esta respuesta y esta respuesta para obtener más información, incluida una explicación de lo anterior, y alternativas que funcionan si se garantiza que su comando producirá la misma cantidad de datos de salida que de entrada. o menos (p.ej, grep, o cut). Estas respuestas tienen la ventaja de que no requieren ningún espacio libre (o requieren muy poco). Las respuestas de arriba del formulario
    commandinput_file > temp_file && …
    requieren claramente que haya suficiente espacio libre para que el sistema pueda contener todo el archivo de entrada (antiguo) y el archivo de salida (nuevo) simultáneamente; esto no es obviamente cierto para la mayoría de las otras soluciones (por ejemplo, sed -i y sponge) así como. Excepción: sort … | dd … probablemente requerirá mucho espacio libre, porque sort necesita leer toda su entrada antes de que pueda escribir cualquier salida, y probablemente almacena la mayoría, si no todos, de esos datos en un archivo temporal.

  • Solo para usuarios avanzados:
    commandinput_file 1<> the_same_file

    puede ser equivalente a la dd respuesta, arriba. los n<>file la sintaxis abre el archivo con nombre en el descriptor de archivo ntanto para entrada como para salida, sin truncarlo, una especie de combinación de n<
    y n>. Nota: algunos programas (p. Ej., cat y grep) pueden negarse a ejecutarse en este escenario porque pueden detectar que la entrada y la salida son el mismo archivo. Vea esta respuesta para una discusión de lo anterior, y un script que hace que esta respuesta funcione si se garantiza que su comando producirá la misma cantidad de datos de salida que de entrada o menos.
    Advertencia: no he probado el guión de Peter, así que no respondo por él.

¿Entonces, cuál era la pregunta?

Este ha sido un tema popular en U&L; se aborda en las siguientes preguntas:

  • ¿Hay alguna forma de modificar un archivo en el lugar?
  • Como puedo hacer iconv reemplazar el archivo de entrada con la salida convertida?
  • ¿Por qué el comando shuf file > file dejar un archivo vacío?
  • ¿Puedo leer y escribir en el mismo archivo en Linux sin sobrescribirlo?
  • Redirigir al mismo archivo que el archivo de origen procesado por el comando
  • ¿Por qué esto sort comando dame un archivo vacío?
  • Redireccionando tr stdout a un archivo
  • grep: el archivo de entrada 'X' también es la salida
  • ¿Los operadores de redirección abren descriptores de archivos en paralelo?
  • La redirección no sobrescribe el archivo, sino que solo produce uno en blanco

… Y eso sin contar Superusuario o Ask Ubuntu. He incorporado mucha información de las respuestas a las preguntas anteriores aquí en esta respuesta, pero no toda. (Es decir, para obtener más información, lea las preguntas mencionadas anteriormente y sus respuestas).

PD tengo no afiliación con el blog que he citado anteriormente.

Más observaciones sobre ;, &, ( y )

  • Tenga en cuenta que algunos de los comandos en la respuesta de terdon pueden ser nulos. Por ejemplo, puedes decir

    command1 ;
    

    (sin command2). Esto es equivalente a

    command1
    

    (es decir, simplemente se ejecuta command1 en primer plano y espera a que se complete. Comparablemente,

    command1 &
    

    (sin command2) pondrá en marcha command1 en segundo plano y luego emita otro indicador de shell inmediatamente.

  • Por el contrario, command1 &&, command1 ||, y command1 | no tiene ningún sentido. Si escribe uno de estos, el shell (probablemente) asumirá que el comando continúa en otra línea. Mostrará el indicador de shell secundario (continuación), que normalmente se establece en >y sigue leyendo. En un script de shell, simplemente leerá la siguiente línea y la agregará a lo que ya ha leído. (Cuidado: puede que esto no sea lo que quieres que suceda).

    Nota: algunas versiones de algunos shells pueden tratar tales comandos incompletos como errores. En tales casos (o, de hecho, en alguna caso en el que tenga un comando largo), puede poner una barra invertida () al final de una línea para decirle al shell que continúe leyendo el comando en otra línea:

    command1  &&  
    command2
    

    o

    find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f 
                            -newer some_existing_file -user fred -readable -print
    
  • Como dice terdon, ( y ) se puede utilizar para agrupar comandos. La afirmación de que "no son realmente relevantes" para esa discusión es discutible. Algunos de los comandos en la respuesta de terdon pueden ser command grupos. Por ejemplo,

    ( command1 ; command2 )  &&  ( command3; command4 )
    

    Haz esto:

    • Correr command1 y espera a que termine.
    • Luego, independientemente del resultado de ejecutar ese primer comando, ejecute command2 y espera a que termine.
    • Entonces sí command2 tuvo éxito,

      • Correr command3 y espera a que termine.
      • Luego, independientemente del resultado de ejecutar ese comando, ejecute command4 y espera a que termine.

      Si command2 falló, deje de procesar la línea de comando.

  • Fuera de paréntesis, | se une muy fuerte, por lo que

    command1 | command2 || command3
    

    es equivalente a

    ( command1 | command2 )  ||  command3
    

    y && y || atar más fuerte que ;, asi que

    command1 && command2 ; command3
    

    es equivalente a

    ( command1 && command2 ) ;  command3
    

    es decir, command3 se ejecutará independientemente del estado de salida de command1 y / o command2.

Reseñas y puntuaciones

Si te animas, tienes la libertad de dejar una crónica acerca de qué te ha gustado de esta sección.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *