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.

¿Fue útil?

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top