manipular parámetros en sh
Pregunta
Estoy trabajando con una utilidad (unísono, pero ese no es el punto) que acepta parámetros como:
$ unison -path path1 -path path2 -path path3
Me gustaría escribir un guión SH que pudiera ejecutar así:
$ myscript path1 path2 path3
Espero una solución compatible con Posix, pero Bash, específica de Bash, también sería bueno.
Supongo que debería ser algo como:
#!/bin/sh
unison ${*/ / -path }
Pero esto no funciona.
EDITAR: Ok, creo que tengo algo:
#!/bin/bash
PARAMS=
for arg in "$@"
do
PARAMS+=" -path '$arg'"
done
unison $PARAMS
Los problemas son que esto solo funciona en Bash, y estoy bastante seguro de que hay una mejor manera de citar los parámetros.
Solución
Sin control, podría ser tan simple como:
exec unison -path $1 -path $2 -path $3
Si no incorpora espacios en los nombres de su ruta, puede lidiar con un número variable de argumentos con:
arglist=""
for path in "$@"
do
arglist="$arglist -path $path"
done
exec unison $arglist
Si tiene espacios en los nombres de su ruta, entonces debe trabajar mucho más; Normalmente uso un programa personalizado llamado escape
, que cita argumentos que necesitan citar, y eval
:
arglist=""
for path in "$@"
do
path=$(escape "$path")
arglist="$arglist -path $path"
done
eval exec unison "$arglist"
Observo que usar Perl o Python facilitaría el manejo de argumentos con espacios en ellos, pero la pregunta pregunta sobre Shell.
También puede ser factible en Bash usar una variable de matriz de shell: incorpore los argumentos en una matriz y pase la matriz como argumentos al unison
dominio.
Otros consejos
Si usa las matrices de Bash, todos sus problemas de cotización desaparecen.
#!/bin/bash
args=()
for i in "$@"; do
# With Bash >= 3:
args+=(-path "$i")
# +=() doesn't work in Bash 2
# args=("${args[@]}" -path "$i")
done
exec unison "${args[@]}"
En Bash, puedes usar "${@/#/-path }"
que reemplazará el comienzo de cada parámetro posicional con "-path". Para representar el final del uso de la cadena %
en vez de #
.
Aquí hay un script de demostración simple usando sed
y repetido -e
opciones. (Por supuesto que hay formas más eficientes de usar sed
.)
#!/bin/bash
echo "Resulting arguments: ${@/#/-e }"
sed "${@/#/-e }"
Y ejecutarlo así:
$ echo abc | demo s/a/A/ s/b/B/
Obtenemos:
Resulting arguments: -e s/a/A/ -e s/b/B/
ABc
Si desea una versión muy específica de Bash, puede probar
#! /bin/sh eval eval exec \ unison -path\\ \\\"{$(eval echo \\\"\\\${1..$#}\\\" | sed 's/ /,/g')}\\\"
Si elimina todos los personajes citados por triple backslash, esto se vuelve más fácil de entender, pero no estropearé la diversión explicándola :-)
La complicación principal es manejar los nombres de los archivos con espacios. Eso explica las cotizaciones de triple-backlash y doble eval.
Así es como puedes citar satisfactoriamente a tus personajes:
job_strategy()
{
local p
for p in "$@"; do
printf '-path\000%s\000' "$p"
done
}
job_process()
{
xargs -0 unison
}
job_strategy "path1" "path2" "path3" | job_process