Passando argumentos para o shell fornecido pelo su

6

man su diz:

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

man bash diz:

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

Bem, então vamos ver:

[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

O que eu esperava (a saída do segundo comando é diferente):

[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

Provavelmente não é um problema. Mas o que está acontecendo lá? A segunda e a terceira variantes parecem o caminho a seguir, mas uma delas não funciona. O quarto parece não ser confiável, - pode ser tratado como a opção su .

    
por x-yuri 05.04.2014 / 23:09

2 respostas

7

O que está acontecendo é que o primeiro argumento que você fornece ao shell é o parâmetro $0 (geralmente, esse seria o nome do shell). Ele não é incluído quando você faz echo $* , já que $* é todo argumento além de $0 .

Exemplo:

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

Atualizar

Fazendo o seguinte comando:

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

produz a linha strace:

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

Então, de alguma forma, parece que, neste caso, su está devorando o -- extra sem passá-lo para o bash, possivelmente devido a um bug (ou pelo menos ao comportamento não documentado). No entanto, ele não consumirá mais do que dois dos argumentos -- :

# su - graeme -c 'echo "\
strace -f su graeme -c 'echo $0; echo "$*"' -- -- 1 2 3
- $0"; echo "\$* - $*"' -- sh 1 2 3 $0 - sh $* - 1 2 3
    
por 05.04.2014 / 23:13
3

Na verdade, a resposta do @Greme - e sua pergunta - estão apenas referenciando os efeitos colaterais de como o shell lida com "$@positional $*parameters". Estes são atribuídos pelo shell aos seus argumentos após a invocação e a qualquer momento mais tarde com oset utilidade. Eles podem ser chamados a qualquer momento com "$*" , que divide cada posição com o primeiro caractere em "$IFS" ou "$@" , que cita cada posição e os divide com "$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 você já tem os valores que você está alimentando o shell, você não precisa -- três vezes. Os parâmetros do shell são set able - sempre, a qualquer momento, não apenas na invocação (exceto $ 0 e -i):

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

7 8 9
4 5 6

E todas essas citações de shell podem ser confusas. Isso simplifica um pouco as coisas:

( 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

Os argumentos do shell pai são set a 4, 5 e 6 e são então passados para o subshell invocado por su via posicional parameter "$@array".

Note como eu ( subshell ) o comando acima - eu faço isso porque eu não quero mexer com o meu ambiente shell atual - porque eu posso alterar inadvertidamente algo que eu prefiro não se eu fiz com set.

SOBRE REDIRECIONAMENTO:

Primeiro de tudo, o seu sistema Unix trabalha com arquivos - permissões de arquivo, conteúdo de arquivo, atributos de arquivo. De uma forma ou de outra, todo objeto de dados que você usa pode (e, pelo menos na minha opinião, deveria) ser endereçado como um arquivo. Redirecionamento aponta para um arquivo - isso é tudo. Um <<HERE-DOCUMENT descreverá um arquivo in-line e o redirecionará. As expansões de shell são interpretadas ou não são.

O participante observa nos comentários abaixo que quando ele tenta usar esse método como o usuário root , ele recebe um erro de permissão. Quando respondi, sugeri que ele chown ou chgrp o arquivo /dev/fd/${num} especial, mas esse provavelmente não é o melhor método. O motivo pelo qual ele encontra esse problema é que root recebe read permissões, mas não execute permissões. Você pode facilmente lidar com isso evitando apenas uma chamada exec . Em vez de invocar o arquivo /dev/fd/${num} diretamente na linha de comando, faça:

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

Usar dois heredocs pode ajudar a escapar. Aqui está o que acontece em todos os casos:

SEM SET EM <<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

OUTPUT

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

OUTPUT

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 MAIS EM <<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

OUTPUT

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
"$@"            $@              \$@             $@
"\$@"  
    
por 07.04.2014 / 03:29