Agregue argumentos a 'bash -c'

22

Digamos que quiero ejecutar un comando a través de Bash como este:

/bin/bash -c "ls -l"

Según la página de manual de Bash, también podría ejecutarlo así:

#               don't process arguments after this one
#               |   pass all unprocessed arguments to command
#               |   |
#               V   V
/bin/bash -c ls -- -l

excepto que no parece funcionar (parece ignorado). ¿Estoy haciendo algo mal o estoy interpretando mal la página del manual?

Citas relevantes del hombre:

Si la opción -c está presente, los comandos se leen de la cadena. Si hay argumentos después de la cadena, se asignan a los parámetros posicionales, comenzando con $ 0.

y

A: señala el final de las opciones y desactiva el procesamiento adicional de opciones. Cualquier argumento después de - se trata como nombres de archivo y argumentos.

Slartibartfast
fuente

Respuestas:

33

Estás interpretando mal la página del manual. En primer lugar, la parte sobre --señalar el final de las opciones es irrelevante para lo que intentas hacer. A -cpartir de ese momento, anula el resto de la línea de comando, de modo que ya no pasa por el manejo de opciones de bash, lo que significa que pasará --al comando, no se manejará por bash como un marcador de fin de opciones.

El segundo error es que los argumentos adicionales se asignan como parámetros posicionales al proceso de shell que se inicia, no se pasan como argumentos al comando. Entonces, lo que está tratando de hacer podría hacerse como uno de:

/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar

En el primer caso, pasar echo los parámetros $0y $1explícitamente, y en el segundo caso, usar "$@"para expandir tan normal como "todos los parámetros posicionales excepto $ 0". Tenga en cuenta que en ese caso también tenemos que pasar algo para ser utilizado $0; Elegí "bash" porque eso es lo $0que normalmente sería, pero cualquier otra cosa funcionaría.

En cuanto a la razón por la que se hace de esta manera, en vez de pasar los argumentos que dan directamente a la orden que la lista: nota de que la documentación dice "comando s se leen de cadena", en plural. En otras palabras, este esquema le permite hacer:

/bin/bash -c 'mkdir "$1"; cd "$1"; touch "$2"' bash dir file

Pero, tenga en cuenta que una mejor manera de alcanzar su objetivo original podría ser usar en envlugar de bash:

/usr/bin/env -- "ls" "-l"

Si no necesita ninguna de las funciones que proporciona un shell, no hay razón para usarla; enven este caso, el uso será más rápido, más simple y menos tipeo. Y no tiene que pensar tanto para asegurarse de que manejará de forma segura los nombres de archivo que contienen metacaracteres de shell o espacios en blanco.

Godlygeek
fuente
3

No estoy seguro de cuál es su objetivo, pero si simplemente está tratando de construir una máquina Rube Goldberg : “un artilugio, invención, dispositivo o aparato que está deliberadamente diseñado o exagerado para realizar una tarea muy simple en un moda complicada "- luego intente

sh -c 'ls $0' -l

o

sh -c 'ls $1' supercalifragilisticexpialidocious -l

o incluso

sh -c 'ls -$0' l

Debería poder entender cómo funcionan estos a partir de la respuesta de Godlygeek.

Scott
fuente