Passando argomenti alla shell fornita


8

man su dice:

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

man bash dice:

--        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 --.

Bene, allora vediamo:

[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

Cosa mi aspettavo (l'output del secondo comando differisce):

[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

Probabilmente non è un grosso problema. Ma cosa sta succedendo lì? La seconda e la terza variante sembrano la strada da percorrere, ma una di esse non funziona. Il quarto sembra inaffidabile, -può essere trattato come suopzione.


È strano. Ottengo esattamente i risultati che ti aspetti (e sono anche d'accordo con quelle aspettative). Voglio dire, in caso di una seconda invocazione, ottengo "1 2 3" come output. Sto usando bash 4.2.45su entrambi gli account di origine e destinazione.
Krzysztof Adamski,

Risposte:


9

Quello che sta succedendo è che il primo argomento fornito alla shell è il $0parametro (di solito questo sarebbe il nome della shell). Non è incluso quando lo fai echo $*poiché $*è ogni argomento a parte $0.

Esempio:

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

Aggiornare

Eseguendo il seguente comando:

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

restituisce la linea di striatura:

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

Quindi in qualche modo sembra che in questo caso sustia divorando il extra --senza passarlo alla bash, probabilmente a causa di un bug (o almeno un comportamento non documentato). Tuttavia non divorerà più di due degli --argomenti:

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

Che ho capito. Sì: su - yuri -c 'echo "$*"' -- -- 1 2 3presumibilmente la shell ottiene -- 1 2 3, ma produce solo output 2 3. Ha senso?
x-yuri,

E quando lo faccio bash -c 'echo $*' -- 1 2 3, esce 1 2 3come previsto.
x-yuri,

@ x-yuri, aggiornato. Questo sembra essere un subug.
Graeme,

5

In realtà la risposta di @ Graeme - e la tua domanda - fanno semplicemente riferimento agli effetti collaterali di come la shell gestisce "$@positional $*parameters".Questi sono assegnati dalla shell ai suoi argomenti su invocazione e in qualsiasi momento successivo con l' setutilità integrata . Possono essere richiamati in qualsiasi momento con uno "$*"che divide ogni posizione con il primo carattere "$IFS"o "$@"che cita ogni posizione e li divide con tutti i"$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

Se hai già i valori che stai alimentando la shell, non è necessario per --tre volte. I parametri della shell sono in setgrado - sempre, in qualsiasi momento, non solo all'invocazione (tranne $ 0 e -i):

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

7 8 9
4 5 6

E tutte quelle citazioni di shell possono essere confuse. Questo semplifica un po 'le cose:

( 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

Gli argomenti della shell genitore sono set4, 5 e 6 e vengono quindi passati alla subshell invocata sutramite la posizionaleparameter "$@array".

Nota come ho ( subshell )il comando sopra - lo faccio perché non voglio fare casino con il mio attuale ambiente shell - perché posso inavvertitamente cambiare qualcosa che preferirei non fare se lo facessiset.

INFORMAZIONI SUL REDIRECTION:

Prima di tutto, il tuo sistema Unix funziona con i file - permessi dei file, contenuto dei file, attributi dei file. In un modo o nell'altro, ogni oggetto dati che usi può (e, almeno secondo me, dovrebbe) essere indirizzato come un file. Il reindirizzamento punta a un file: tutto qui. A <<HERE-DOCUMENTdescriverà un file in linea, quindi lo reindirizzerà. Le espansioni della shell vengono interpretate o non lo sono.

Nei commenti che seguono, il richiedente chiede che quando tenta di utilizzare questo metodo come rootutente gli viene consegnato un errore di autorizzazione. Quando ho risposto ho suggerito lui chowno chgrpil /dev/fd/${num}file speciale, ma questo probabilmente non è il metodo migliore. Il motivo per cui riscontra questo problema rootè concesso readautorizzazioni ma non execute autorizzazioni. Puoi gestirlo facilmente evitando una execchiamata. Invece di invocare il /dev/fd/${num}file direttamente dalla riga di comando fai:

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

L'uso di due heredocs può aiutare a fuggire. Ecco cosa succede in ogni caso:

NO SET IN <<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

PRODUZIONE

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

PRODUZIONE

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 "$@"E ALTRO 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

PRODUZIONE

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
"$@"            $@              \$@             $@
"\$@"  

Il problema è che il tuo primo copione mi dà "8 9\n4 5 6\n". Io corro debian 6, bash-4.1.5e su.
x-yuri,

@ x-yuri - e il secondo, che evita tutto il disordine delle citazioni?
Mikeserv,

Se eseguito da rootesso dice: -su: /dev/fd/4: Permission denied. Sai cosa significa, a proposito? Altrimenti emette come dici tu, ma non affronta la domanda. La domanda riguarda l'uso di --e -.
x-yuri,

@ x-yuri Penso che ciò significhi che dovresti chown /dev/fd/4per tutto il tempo che ti servirà, o semplicemente chgrp. Non ho molto tempo per testare adesso. Ma questo è un po 'a parte il punto, come è stato l'altro non è necessario passare argomenti alla fine della coda - basta lavorare la tua citazione. Vedi adesso?
Mikeserv,

Se omettiamo il problema superché non riusciamo a lavorare con il reindirizzamento stdin, passare gli argomenti è ancora meglio quindi immetterli nel comando. Perché in quest'ultimo caso devi fuggire.
x-yuri,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.