Übergeben von Argumenten an die von su bereitgestellte Shell

8

man su sagt:

You can use the -- argument to separate su options from the arguments
supplied to the shell.

man bash sagt:

--        A  --  signals  the  end of options and disables further option
          processing.  Any arguments after the -- are treated as filenames
          and arguments.  An argument of - is equivalent to --.

Na dann mal sehen:

[root ~] su - yuri -c 'echo "$*"' -- 1 2 3
2 3
[root ~] su - yuri -c 'echo "$*"' -- -- 1 2 3                                                       
2 3
[root ~] su - yuri -c 'echo "$*"' -- - 1 2 3                                                        
1 2 3
[root ~] su - yuri -c 'echo "$*"' - 1 2 3                                                           
1 2 3

Was ich erwartet habe (Ausgabe des zweiten Befehls ist unterschiedlich):

[root ~] su - yuri -c 'echo "$*"' -- 1 2 3
2 3
[root ~] su - yuri -c 'echo "$*"' -- -- 1 2 3                                                       
1 2 3
[root ~] su - yuri -c 'echo "$*"' -- - 1 2 3                                                        
1 2 3
[root ~] su - yuri -c 'echo "$*"' - 1 2 3                                                           
1 2 3

Wahrscheinlich kein großes Problem. Aber was passiert dort? Die zweite und die dritte Variante scheinen der richtige Weg zu sein, aber eine davon funktioniert nicht. Der vierte scheint unzuverlässig, -kann als suOption behandelt werden.

x-yuri
quelle
Das ist seltsam. Ich erhalte genau die Ergebnisse, die Sie erwarten (und ich stimme diesen Erwartungen auch zu). Ich meine, im Falle eines zweiten Aufrufs bekomme ich "1 2 3" als Ausgabe. Ich verwende bash 4.2.45sowohl für Quell- als auch für Zielkonten.
Krzysztof Adamski

Antworten:

9

Was passiert ist, dass das erste Argument, das Sie der Shell geben, der $0Parameter ist (normalerweise ist dies der Name der Shell). Es ist nicht enthalten, wenn Sie dies tun, echo $*da $*jedes Argument außer $0.

Beispiel:

# su - graeme -c 'echo "\$0 - $0"; echo "\$* - $*"' -- sh 1 2 3
$0 - sh
$* - 1 2 3

Aktualisieren

Führen Sie den folgenden Befehl aus:

strace -f su graeme -c 'echo $0; echo "$*"' -- -- 1 2 3

ergibt die Strace-Linie:

[pid  9609] execve("/bin/bash", ["bash", "-c", "echo $0; echo \"$*\"", "1", "2", "3"], [/* 27 vars */] <unfinished ...>

Es scheint also, dass in diesem Fall sudas Extra verschlungen wird, --ohne es an Bash weiterzugeben, möglicherweise aufgrund eines Fehlers (oder zumindest eines undokumentierten Verhaltens). Es wird jedoch nicht mehr als zwei der --Argumente auffressen :

# su graeme -c 'echo $0; echo "$*"' -- -- -- 1 2 3
--
1 2 3
Graeme
quelle
Das verstehe ich. Ich mache : su - yuri -c 'echo "$*"' -- -- 1 2 3, die Shell bekommt angeblich -- 1 2 3, gibt aber nur aus 2 3. Macht es überhaupt Sinn?
X-Yuri
Und wenn ich es tue bash -c 'echo $*' -- 1 2 3, wird es 1 2 3wie erwartet ausgegeben.
X-Yuri
@ x-yuri, aktualisiert. Dies scheint ein suFehler zu sein.
Graeme
5

Tatsächlich bezieht sich die Antwort von @ Graeme - und Ihre Frage - nur auf Nebenwirkungen der Handhabung der Shell. "$@positional $*parameters".Diese werden von der Shell beim Aufruf und zu einem späteren Zeitpunkt mit dem integrierten setDienstprogramm ihren Argumenten zugewiesen . Sie können jederzeit aufgerufen werden, indem entweder "$*"jede Position mit dem ersten Zeichen in geteilt wird "$IFS"oder "$@"jede Position zitiert und mit allen geteilt wird"$IFS."

man set

    NAME
       set  set or unset options and positional parameters

SYNOPSIS
       set [−abCefhmnuvx] [−o option] [argument...]

       set [+abCefhmnuvx] [+o option] [argument...]

       set −− [argument...]

       set o

       set +o

Wenn Sie bereits die Werte haben, mit denen Sie die Shell füttern, müssen Sie dies nicht --dreimal tun . Shell-Parameter sind in der setLage - immer und jederzeit, nicht nur beim Aufruf (außer $ 0 und -i):

su - mikeserv -c 'set -- "$*" ; echo "$*" ; 
    set -- 4 5 6 ; echo "$*"' -- -- 7 8 9

7 8 9
4 5 6

Und all diese Shell-Zitate können verwirrend sein. Dies vereinfacht die Dinge ein wenig:

( set -- 4 5 6
    su - mikeserv 4<<-\CMD /dev/fd/4 "$@"
    echo $0 "$*"
    set -- "$*"
    echo "$*"
    set -- 7 8 9
    echo "$*"
CMD
)

/dev/fd/4 4 5 6
4 5 6
7 8 9

Die Argumente der übergeordneten Shell lauten set4, 5 und 6 und werden dann an die Subshell übergeben, die von suüber die Position aufgerufen wirdparameter "$@array".

Beachten Sie, wie ich ( subshell )den obigen Befehl verwende - ich mache das, weil ich nicht mit meiner aktuellen Shell-Umgebung herumspielen möchte -, weil ich versehentlich etwas ändern kann, das ich lieber nicht möchte, wenn ich es getan habeset.

ÜBER UMLEITUNG:

Zunächst arbeitet Ihr Unix-System mit Dateien - Dateiberechtigungen, Dateiinhalten, Dateiattributen. Auf die eine oder andere Weise kann (und sollte) jedes von Ihnen verwendete Datenobjekt als Datei adressiert werden. Die Umleitung zeigt auf eine Datei - das ist alles. A <<HERE-DOCUMENTbeschreibt eine Datei inline und leitet sie dann um. Entweder werden Shell-Erweiterungen interpretiert oder nicht.

Der Fragesteller stellt in den Kommentaren unten fest, dass ihm beim Versuch, diese Methode als rootBenutzer zu verwenden, ein Berechtigungsfehler zugestellt wird. Als ich antwortete, schlug ich ihn chownoder chgrpdie /dev/fd/${num}spezielle Datei vor, aber dies ist wahrscheinlich nicht die beste Methode. Der Grund , warum er dieses Thema Begegnungen ist rootist gewährt readBerechtigungen aber nicht execute Berechtigungen. Sie können dies einfach handhaben, indem Sie einfach einen execAnruf vermeiden . Anstatt die /dev/fd/${num}Datei direkt über die Befehlszeile aufzurufen, gehen Sie wie folgt vor:

su -c '. /dev/fd/'${num} ${num}<<SCRIPT 

Die Verwendung von zwei Heredocs kann bei der Flucht helfen. Folgendes passiert in jedem Fall:

KEIN EINSTELLEN <<HEREDOC

sh 3<<\CMD /dev/fd/3
    ( echo 'without set "$@" or \$@ in here-doc' ; echo
    set -- '1 "2" 3' 4 "5 6"
    su - mikeserv 4<<-UNQUOTED 5<<-\PREQUOTED /dev/fd/4
        echo UNQUOTED; echo $0 "$*"
        printf "%s\\t\\t%s\\t\\t%s\\t\\t%s\\n" $(printf "'%s' " "$@") \\
                $@ '$@' "$@" '"$@"' "'$@'" \$@ '\$@' "\$@" '"\$@"'
    . /dev/fd/5
    UNQUOTED
        echo PREQUOTED ; echo $0 "$*"
        printf "%s\t\t%s\t\t%s\t\t%s\n" $(printf "'%s' " "$@") \
                $@ '$@' "$@" '"$@"' \$@ '\$@' "\$@" '"\$@"'
    PREQUOTED
    )
CMD

AUSGABE

without set "$@" or \$@ in here-doc

UNQUOTED
/dev/fd/3 1 2 3 4 5 6
1 "2" 3         4               5 6             1
2               3               4               5
6               1 "2" 3 4 5 6           1 2 3 4 5 6             "1 "2" 3 4 5 6"
'1 2 3 4 5 6'           $@              "$@"
PREQUOTED
/dev/fd/5
''              $@              "$@"            $@
\$@             $@              "\$@"

SET "$@"IN<<HEREDOC

sh 3<<\CMD /dev/fd/3
    ( echo 'set "$@" and \$@ in here-doc' ; echo
    set -- '1 "2" 3' 4 "5 6"
    su - mikeserv 4<<-UNQUOTED 5<<-\PREQUOTED /dev/fd/4
        set -- "$@" "\$@"
        echo UNQUOTED; echo $0 "$*"
        printf "%s\\t\\t%s\\t\\t%s\\t\\t%s\\n" $(printf "'%s' " "$@") \\
                $@ '$@' "$@" '"$@"' "'$@'" \$@ '\$@' "\$@" '"\$@"'
        . /dev/fd/5
    UNQUOTED
        set -- "$@" "\$@"
        echo PREQUOTED ; echo $0 "$*"
        printf "%s\t\t%s\t\t%s\t\t%s\n" $(printf "'%s' " "$@") \
                $@ '$@' "$@" '"$@"' \$@ '\$@' "\$@" '"\$@"'
    PREQUOTED
)
CMD

AUSGABE

set "$@" and \$@ in here-doc

UNQUOTED
/dev/fd/3 1 2 3 4 5 6
1 "2" 3         4               5 6             1
2               3               4               5
6               1 "2" 3 4 5 6           1 2 3 4 5 6             "1 "2" 3 4 5 6"
'1 2 3 4 5 6'           1 2 3 4 5 6             $@              1 2 3 4 5 6
"$@"
PREQUOTED
/dev/fd/5 1 2 3 4 5 6 $@
'1              2               3               4
5               6'              '$@'            1 2 3 4 5 6
$@              $@              1 2 3 4 5 6             $@
"$@"            $@              \$@             $@
"\$@"  

SET "$@"UND MEHR IN<<HEREDOC

sh 3<<\CMD /dev/fd/3
    ( echo 'set "$@" and \$@ AND additional parameters in here-doc' ; echo
    set -- '1 "2" 3' 4 "5 6"
    su - mikeserv 4<<-UNQUOTED 5<<-\PREQUOTED /dev/fd/4
        set -- "$@" "\$@" '7 "8" 9' 10 "11 12"
        echo UNQUOTED; echo $0 "$*"
        printf "%s\\t\\t%s\\t\\t%s\\t\\t%s\\n" $(printf "'%s' " "$@") \\
                $@ '$@' "$@" '"$@"' "'$@'" \$@ '\$@' "\$@" '"\$@"'
        . /dev/fd/5
    UNQUOTED
        set -- "$@" "\$@" '13 "14" 15' 16 "17 18"
        echo PREQUOTED ; echo $0 "$*"
        printf "%s\t\t%s\t\t%s\t\t%s\n" $(printf "'%s' " "$@") \
                $@ '$@' "$@" '"$@"' \$@ '\$@' "\$@" '"\$@"'
    PREQUOTED
    )
CMD

AUSGABE

set "$@" and \$@ AND additional parameters in here-doc

UNQUOTED
/dev/fd/3 1 2 3 4 5 6
1 "2" 3         4               5 6             1
2               3               4               5
6               1 "2" 3 4 5 6           1 2 3 4 5 6             "1 "2" 3 4 5 6"
'1 2 3 4 5 6'           1 2 3 4 5 6             7 "8" 9         10
11 12           $@              1 2 3 4 5 6             7 "8" 9
10              11 12           "$@"
PREQUOTED
/dev/fd/5 1 2 3 4 5 6 7 "8" 9 10 11 12 $@ 13 "14" 15 16 17 18
'1              2               3               4
5               6'              '7              "8"
9'              '10'            '11             12'
'$@'            '13             "14"            15'
'16'            '17             18'             1 2 3 4 5 6
7 "8" 9         10              11 12           $@
13 "14" 15              16              17 18           $@
1 2 3 4 5 6             7 "8" 9         10              11 12
$@              13 "14" 15              16              17 18
"$@"            $@              \$@             $@
"\$@"  
mikeserv
quelle
Das Problem ist, dass dein erstes Skript mir gibt "8 9\n4 5 6\n". Ich laufe debian 6, bash-4.1.5und su.
X-Yuri
@ x-yuri - und die zweite, die das ganze Zitier-Chaos vermeidet?
Mikeserv
Wenn davon weggelaufen root, heißt es : -su: /dev/fd/4: Permission denied. Wissen Sie übrigens, was das bedeutet? Andernfalls wird ausgegeben, wie Sie sagen, aber die Frage wird nicht beantwortet. Frage ist über die Verwendung von --und -.
X-Yuri
@ x-yuri Ich denke, das bedeutet, dass du es chown /dev/fd/4für die Dauer tun solltest, die du brauchst, oder einfach chgrp. Ich habe momentan nicht viel Zeit zum Testen. Aber das ist ein wenig nebensächlich, ebenso wie das andere, bei dem Sie überhaupt keine Argumente am hinteren Ende übergeben müssen - arbeiten Sie einfach an Ihrem Zitat. Sieh es jetzt?
Mikesserv
Wenn wir das Problem auslassen, dass wir sunicht mit umgeleiteten arbeiten können stdin, ist es immer noch besser, Argumente zu übergeben, als sie in den Befehl einzufügen. Denn im letzteren Fall müssen Sie ihnen entkommen.
X-Yuri