2009-06-08 16 views
4

Ich bin mit einem Dienstprogramm arbeiten (unison, aber das ist nicht der Punkt), die Parameter wie akzeptiert:in sh Parameter manipulieren

$ unison -path path1 -path path2 -path path3 

Ich möchte ein sh-Skript schreiben, die ich so laufen könnte:

$ myscript path1 path2 path3 

ich hoffe auf eine Posix-konforme Lösung, aber bash-spezifische wäre auch gut.

Ich vermute, es etwas sein sollte:

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

Aber das funktioniert nicht.

EDIT: OK, ich glaube ich etwas bekam:

#!/bin/bash 
PARAMS= 
for arg in "[email protected]" 
do 
    PARAMS+=" -path '$arg'" 
done 
unison $PARAMS 

Die Probleme sind dies funktioniert nur in bash, und ich bin mir ziemlich sicher, dass es einen besseren Weg, um die Parameter zu zitieren.

+0

Sind Sie hoffen auf eine One-Line-Lösung, die keine "for" -Schleife beinhaltet? – eduffy

+0

Jede Lösung wirklich – itsadok

+0

Die Einführung der einfachen Anführungszeichen ist wahrscheinlich eine schlechte Idee. Wie geschrieben, werden die Zitate durch den Unison-Befehl gesehen, was nicht das ist, was Sie wollen. Das Äußere des Arguments mit einfachen Anführungszeichen zu schützen, ist OK, wenn Sie keine einfachen Anführungszeichen in den Argumenten haben - aber Sie benötigen wahrscheinlich ein Eval, damit es korrekt funktioniert. –

Antwort

5

Ungeprüft, könnte es so einfach sein wie:

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

Wenn Sie Leerzeichen im Pfadnamen nicht einbetten kann, dann können Sie mit einer variablen Anzahl von Argumenten befassen sich mit:

arglist="" 
for path in "[email protected]" 
do 
    arglist="$arglist -path $path" 
done 
exec unison $arglist 

Wenn Sie Leerzeichen in Ihren Pfadnamen haben, müssen Sie viel härter arbeiten. Normalerweise verwende ich ein benutzerdefiniertes Programm namens escape, die Argumente zitiert, die unter Angabe benötigen, und eval:

arglist="" 
for path in "[email protected]" 
do 
    path=$(escape "$path") 
    arglist="$arglist -path $path" 
done 
eval exec unison "$arglist" 

Ich stelle fest, dass Perl oder Python würde Handhabung Argumente mit Leerzeichen in ihnen leichter machen - aber die Frage fragt nach Shell.

Es könnte auch in Bash möglich sein, eine Shell-Array-Variable zu verwenden - bauen Sie die Argumente in einem Array auf und übergeben Sie das Array als Argumente an den Befehl unison.

1

Wenn Sie eine stark bash-spezifische Version möchten, können Sie versuchen,

 
#! /bin/sh 

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

Wenn Sie alle Triple-Backslash zitierten Zeichen entfernen, wird dies leichter zu verstehen, aber ich werde den Spaß nicht verderben indem man es erklärt :-)

Die Hauptkomplikation ist, Aktennamen mit Räumen zu behandeln. Das erklärt das Triple-Backlash-Quoting und Double-Eval.

+0

Upvoted für verrückte One-Liner – itsadok

+0

WTF? Wenn Sie Bash-spezifisch sein wollen, ist die richtige Sache, Arrays zu verwenden - auf diese Weise erhalten Sie den Vorteil eines einfachen, leicht zu lesenden Codes, der klar geschrieben werden kann, um offensichtlich keine Fehler zu haben, anstatt sie zu benötigen sich darauf zu verlassen, keine offensichtlichen Fehler zu haben. –

+0

Diese Antwort sollte seltsam, kryptisch und humorvoll sein, kein Beispiel für das "Richtige". – Idelic

4

Wenn Sie Bash-Arrays verwenden, verschwinden alle Ihre Angebotsprobleme.

#!/bin/bash 
args=() 
for i in "[email protected]"; do 
    # With Bash >= 3: 
    args+=(-path "$i") 
    # +=() doesn't work in Bash 2 
    # args=("${args[@]}" -path "$i") 
done 
exec unison "${args[@]}" 
+0

+1 für Arrays statt chaotisch und zerbrechlich Zitate/Escapes –

+0

Dito @Gordon, plus danke für die Aufnahme der Bit über Bash 2 Kompatibilität! –

3

In Bash, können Sie "${@/#/-path }", die mit „-Pfad“ den Beginn eines jeden Positionsparameter ersetzen wird. Um das Ende der Zeichenfolge darzustellen, verwenden Sie % anstelle von #.

Hier ist ein einfaches Demo-Skript mit sed und wiederholte -e Optionen.(. Natürlich gibt es effizientere Wege sed zu verwenden)

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

Und es wie folgt ausgeführt werden:

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

Wir erhalten:

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

Hier ist, wie Sie können satisfyingly Zitat Ihre Zeichen:

job_strategy() 
{ 
    local p 
    for p in "[email protected]"; do 
    printf '-path\000%s\000' "$p" 
    done 
} 

job_process() 
{ 
    xargs -0 unison 
} 

job_strategy "path1" "path2" "path3" | job_process 
+1

+1. Das heißt, ist "xargs-0" POSIX? Mein Eindruck ist, dass es eine GNU-Erweiterung ist. –

+0

Laut der FreeBSD-Manpage 'xargs -0' ist POSIX. –

+0

Es ist nicht aufgeführt in http://pubs.opengroup.org/onlinepubs/009696699/utilities/xargs.html –