Comprender la sustitución de comandos complejos con {} y múltiples `\ls`

Comprender la sustitución de comandos complejos con {} y múltiples `\ls`

Estoy tratando de entender esta línea desde un script de shell. Sé que eso $(..)significa ejecutar ..e insertar su salida donde la encuentre $()en una declaración. Pero ¿qué pasa entre esos paréntesis? ¿Qué es el \lshacer y cómo se relaciona con lo \de las líneas anteriores? ¿Es eso una \\división en dos líneas? ¿Es \lslo mismo que el normal ls?

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

Respuesta1

La salida de los 3 lscomandos se pasa al pastecomando que los fusiona en el valor:

$VOLTDB_VOLTDB"/voltdb-*.jar:$VOLTDB_LIB"/*.jar:$VOLTDB_LIB"/extension/*.jar

NOTA:Las variables $VOLTDB_VOLTDBy $VOLTDB_LIBse expandirán y puede haber más valores que un solo archivo para cada uno de estos lscomandos. ¿Ves *ahí? Es un carácter global que actúa como comodín y se expande a cualquier cosa entre el lado izquierdo (voltdb-) y el lado derecho (.jar), por ejemplo.

Estos coincidirían:

voltdb-1.jar
voltdb-blah.jar
voltdb-12345.jar

Entonces todo se incluye en la variable APPCLASSPATH:

APPCLASSPATH=$CLASSPATH:$VOLTDB_VOLTDB"/voltdb....etc.

El comando pegar

Aquí hay un ejemplo en el que estoy usando el seqcomando para generar una secuencia de números, del 1 al 10.

$ seq 10 | paste -sd ':' -
1:2:3:4:5:6:7:8:9:10

Puede ver que el pastecomando fusiona la salida y la separa con dos puntos ( :).

También puedes imitar el comando de ejemplo de esta manera:

$ { echo "hi1"; echo "hi2"; echo "hi3"; } | paste -sd ':' -
hi1:hi2:hi3

NOTA:El -comando pegar le indica que tome la entrada de STDIN e imprima cada argumento a medida que ingresa, separado por un archivo :.

Con diferentes cambios pastetambién se puede dividir los datos en grupos, según el número de -'s que siguen.

Pegar ejemplos

Aquí hay un ejemplo con 2 -.

$ seq 10 | paste - -
1       2
3       4
5       6
7       8
9       10

Aquí hay 3 -.

$ seq 10 | paste - - -
1       2       3
4       5       6
7       8       9
10

Entonces indica pastecuántos argumentos pastedeben imprimirse en cada línea. Pero no se confunda, el ejemplo que está tratando es simplemente tomar la entrada de STDIN, separar cada argumento en espacios e imprimirlo seguido de un archivo :. Al dar varios -, le está diciendo pasteque tome argumentos, 2 y a la vez, 3 a la vez, etc.

Argumentos 2 a la vez, separados por :'s:

$ seq 10 | paste -d ':' - -
1:2
3:4
5:6
7:8
9:10

$ seq 10 | paste -d ':' - - -
1:2:3
4:5:6
7:8:9
10::

Por cierto, si incluye el -smodificador, le está indicando pasteque tome los argumentos en serie (en serie). Observe lo que sucede cuando lo usa en uno de los ejemplos anteriores.

2 a la vez:

$ seq 10 | paste -sd ':' - -
1:2:3:4:5:6:7:8:9:10

3 a la vez:

$ seq 10 | paste -sd ':' - - -
1:2:3:4:5:6:7:8:9:10

Respuesta2

$(command)ejecuta un comando y sustituye su salida.

{ list; }es un comando de grupo que ejecuta varios comandos en el entorno de shell actual. Es similar a (list), pero no forma una subcapa.

\commandse utiliza para ignorar alias de comandos, lo que puede alterar considerablemente el comportamiento esperado de un comando.

Al \final de la línea simplemente significa que esta línea continúa, por lo que el shell verá la siguiente línea como parte de la actual. Generalmente no es necesario cuando esto es obvio por el contexto (paréntesis abierto o cita).

Respuesta3

APPCLASSPATH=$CLASSPATH:$({ \
    \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
    \ls -1 "$VOLTDB_LIB"/*.jar; \
    \ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )

\lses como ls, excepto que si lses un alias, la barra invertida evita la expansión del alias. Esto garantiza que lsse utilice el comando y no algún alias que pueda agregar resultados no deseados, como un sufijo clasificador ( -F).

Los lscomandos, llamados con nombres de archivos existentes como argumentos, enumeran sus argumentos, uno por línea. La opción -1no tiene ningún efecto ya que la salida de lsva a una tubería y no a una terminal. Si lsrecibe un argumento que no es el nombre de un archivo existente, no muestra nada en su salida estándar y en su lugar muestra un error. Los errores de los lscomandos se redirigen a ninguna parte mediante 2> /dev/null. Hay dos razones por las que lsse puede recibir un argumento que no es un archivo: si una de las variables no hace referencia a un directorio existente y legible, o si no hay ningún archivo que coincida con el patrón comodín. En cualquier caso, el patrón se pasa sin expandir a ls.

Las barras invertidas al final de las líneas hacen que el shell ignore la siguiente nueva línea. Ninguno de ellos es útil aquí ya que en cada punto donde se utilizan, el shell espera una nueva línea opcional.

Las llaves {...} agrupan los comandos. El comando compuesto { \ls …; \ls …; \ls … ; }se canaliza pastey sus errores se redirigen a /dev/null.

El pastecomando une todas las líneas de entrada con un :punto intermedio. Equivale a tr '\n' :excepto que no pone a :al final.

La sustitución del comando $(…)hace que la salida de pastese interpole en APPCLASSPATH, después del valor de la CLASSPATHvariable con dos puntos para separar las dos partes.

Aquí hay una versión simplificada. Esto es ligeramente diferente del original en que si ninguno de los patrones comodín coincide con nada, APPCLASSPATHserá igual CLASSPATHsin dos puntos finales adicionales (lo cual probablemente sea deseable).

APPCLASSPATH=$CLASSPATH:$(
  \ls "$VOLTDB_VOLTDB"/voltdb-*.jar "$VOLTDB_LIB"/*.jar "$VOLTDB_LIB"/extension/*.jar |
  tr '\n' :) 2>/dev/null
APPCLASSPATH=${APPCLASSPATH%:}

información relacionada