Domanda

Sto lavorando con un'utilità (Unison, ma non è questo il punto) che accetta parametri come:

$ unison -path path1 -path path2 -path path3

Vorrei scrivere una sceneggiatura che potrei eseguire così:

$ myscript path1 path2 path3

Spero in una soluzione conforme a Posix, ma anche Bash-specifico sarebbe buono.

Immagino che dovrebbe essere qualcosa di simile:

#!/bin/sh
unison ${*/ / -path }

Ma questo non funziona.

MODIFICARE: Ok, penso di avere qualcosa:

#!/bin/bash
PARAMS=
for arg in "$@"
do
    PARAMS+=" -path '$arg'"
done
unison $PARAMS

I problemi sono questo che funziona solo in bash e sono abbastanza sicuro che ci sia un modo migliore per citare i parametri.

È stato utile?

Soluzione

Incontrollato, potrebbe essere semplice come:

exec unison -path $1 -path $2 -path $3

Se non incorpori spazi nei nomi del tuo percorso, puoi gestire un numero variabile di argomenti con:

arglist=""
for path in "$@"
do
    arglist="$arglist -path $path"
done
exec unison $arglist

Se hai spazi nei nomi del tuo percorso, allora devi lavorare molto più duramente; Di solito uso un programma personalizzato chiamato escape, che cita argomenti che devono essere citati e eval:

arglist=""
for path in "$@"
do
    path=$(escape "$path")
    arglist="$arglist -path $path"
done
eval exec unison "$arglist"

Noto che l'uso di Perl o Python renderebbe più facile la gestione di argomenti con spazi, ma la domanda pone su Shell.

Potrebbe anche essere fattibile in bash usare una variabile di array di shell: costruire gli argomenti in un array e passare l'array come argomenti al unison comando.

Altri suggerimenti

Se usi gli array di Bash, tutti i tuoi problemi di citazione scompaiono.

#!/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[@]}"

In Bash, puoi usare "${@/#/-path }" che sostituirà l'inizio di ciascun parametro posizionale con "-path". Per rappresentare la fine dell'uso della stringa % invece di #.

Ecco uno script demo semplice usando sed e ripetuto -e opzioni. (Naturalmente ci sono modi più efficienti per utilizzare sed.)

#!/bin/bash
echo "Resulting arguments: ${@/#/-e }"
sed "${@/#/-e }"

E eseguendolo in questo modo:

$ echo abc | demo s/a/A/ s/b/B/

Noi abbiamo:

Resulting arguments: -e s/a/A/ -e s/b/B/
ABc

Se vuoi una versione pesantemente specifica per bash, puoi provare

#! /bin/sh

eval eval exec \
  unison -path\\ \\\"{$(eval echo \\\"\\\${1..$#}\\\" | sed 's/ /,/g')}\\\"

Se rimuovi tutti i personaggi di tripla backslash, questo diventa più facile da capire, ma non rovinerò il divertimento spiegandolo :-)

La complicazione principale è gestire i nomi dei file con spazi. Ciò spiega la citazione tripla-backlash e il doppio eval.

Ecco come puoi citare in modo soddisfacente i tuoi personaggi:

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top