Shell Script: creando una variable con opciones dentro

11

Tengo un comando rsync con los siguientes parámetros:

rsync -avz --{partial,stats,delete,exclude=".*"}

Quiero poner esos parámetros dentro de una variable para reutilizarlos después en el script. Algo como esto:

#!/bin/bash
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}
$VAR /dir1 /dir2

He intentado con comillas, comillas simples, corchetes, sin ningún éxito.

Kellyson
fuente
Pregunta similar sobre SO: stackoverflow.com/questions/13365553/…
Barmar
Después de haber recorrido esta ruta antes: asegúrese de que la cadena de comando resultante final no tenga cadenas vacías. Si lo hace, rsync puede usarlos como parámetros y, dado que son invisibles, es bastante difícil de depurar. Tenía un primer parámetro vacío y rsync lo interpretó como la inclusión del directorio actual en las fuentes de las cosas para copiar.
Joe

Respuestas:

12

Poner un comando complejo en una variable nunca es un enfoque recomendado. Ver BashFAQ / 050 - Estoy tratando de poner un comando en una variable, ¡pero los casos complejos siempre fallan!

Su requisito se vuelve realmente simple, si simplemente decide usar una función en lugar de una variable y pasarle argumentos.

Algo como

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --{partial,stats,delete,exclude=".*"} "$@"
}

y ahora pasale los argumentos requeridos como

rsync_custom /dir1 /dir2

La definición de la función es bastante simple, primero verificamos el recuento de argumentos de entrada usando la variable $#que no debería ser cero. Lanzamos un mensaje de error que dice que no se proporcionan argumentos. Si hay argumentos válidos, "$@"representa los argumentos reales suministrados a la función.

Si esta es una función que usaría con bastante frecuencia, es decir, en scripts / línea de comandos también, agréguela a los archivos de inicio de la shell .bashrc, .bash_profilepor ejemplo.

O como se señaló, puede valer la pena expandir la expansión de la llave para separar los args para una mejor legibilidad como

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --partial --stats --delete --exclude=".*" "$@"
}
Inian
fuente
5
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

Esto intenta ejecutar el comando -avzcon argumentos --partial, --statsetc. y con VARset to rsyncen el entorno.

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

El formulario entre comillas no funciona porque las llaves no se expanden entre comillas, ni dentro de las asignaciones, y tampoco se expanden después de que se expande una variable.

Si necesita almacenar argumentos de línea de comando en una variable, use una matriz:

args=(rsync -avz --{partial,stats,delete,exclude=".*"})

Ahora "${args[@]}"se expandirá a rsync, -avz, --partial, etc, como palabras distintas.

Las matrices también le permiten agregar opciones a la lista, condicionalmente si es necesario, por lo que puede, por ejemplo:

args=(this that)
if something ; then
    args+=(another_arg)
fi
"$cmd" "${args[@]}"
ilkkachu
fuente
1

Al menos puede guardar las opciones parcialmente en una variable:

opts=$(echo --{ignore-case,word-regexp,count,exclude='"sys*.*"'})

Las pruebas son importantes porque el enmascaramiento puede ser difícil:

echo $opts
--ignore-case --word-regexp --count --exclude="sys*"

grep $opts bytes *.log 

Dado que hay múltiples alternativas, como usar el historial, usar un alias, usar una función, no hay un caso de uso obvio en el que pueda pensar. Rara vez se comparte una opción compleja entre diferentes programas, por lo que para una solución ad-hoc para el shell interactivo, el alias parece una mejor manera:

alias cgrep='grep --ignore-case --word-regexp --count --exclude="sys*"'
cgrep bytes *.log

Su muestra

VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

no puede funcionar, porque la tarea es endet en el primer espacio en blanco. Tienes que enmascarar los espacios en blanco:

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

una cosa bastante peligrosa para las pruebas, con esa opción de eliminación, ¿no es así? Como las opciones pueden contener nuevamente "," y comillas simples, el enmascaramiento puede ser difícil muy pronto. Iría por un alias o confiaría en la historia.

Se puede almacenar un alias en el archivo ~ / .bashrc para su uso continuo en varias sesiones. Las funciones también se pueden almacenar en el bashrc, pero solo las necesita, si desea manejar los parámetros, pasados ​​a la función para ser evaluados allí.

usuario desconocido
fuente