AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 535925
Accepted
sourcejedi
sourcejedi
Asked: 2019-08-17 10:37:35 +0800 CST2019-08-17 10:37:35 +0800 CST 2019-08-17 10:37:35 +0800 CST

"sh -c" não expande parâmetros posicionais, se eu executá-lo de "sudo --login". Existe uma maneira de contornar isso?

  • 772

Eu escrevi um "script embutido" que usa parâmetros posicionais, por exemplo

$ sudo sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
p0=sh
p1=1
p2=2
all=1 2

Na verdade, quero executar meu script embutido usando o sudo --login. Mas então os parâmetros posicionais não funcionam. Existe uma maneira de fazê-los funcionar?

(Também estou interessado se o comportamento está documentado ou padronizado em algum lugar).

$ sudo --login sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
p0=-bash
p1=
p2=
all=1 2

Versões de software:

$ sh --version
GNU bash, version 5.0.7(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ sudo --version
Sudo version 1.8.27
Sudoers policy plugin version 1.8.27
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.27
shell-script sudo
  • 1 1 respostas
  • 494 Views

1 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2019-08-17T12:22:38+08:002019-08-17T12:22:38+08:00

    Pela mesma razão

    sudo --login echo '$HOME'
    

    Não gera $HOME, mas o conteúdo da $HOMEvariável (do usuário de destino, conforme definido por sudo).

    No seu caso, não é porque sh -c não expande os parâmetros posicionais , mas porque os $0, $1, $2já foram expandidos (pelo shell de login) no momento em que shfoi iniciado.

    O que é mais surpreendente aqui é por que você vê all=1 2. E é a mesma razão pela qual você $@vê sudo --login echo '$@'.

    Ambos -s/ --shelle -i/ --loginexecutam um shell para executar o comando. Mas sudofaz isso de uma maneira muito estranha.

    Eu esperaria sudo -s 'some shell code'executar um shell para interpretar some shell code, mas não é isso que ele faz. Com -s, ele ainda espera executar um único comando simples e tenta citar (com \) alguns caracteres na esperança de fazer isso acontecer por meio desse shell.

    Você não está destinado a fazer sudo -s 'echo test', mas sudo -s echo test. No primeiro caso, sudo realmente passa echo\ testcomo código shell. Em shells do tipo Bourne, isso tenta executar um comando chamado 'echo test'. Com um rcshell, isso executaria um comando chamado echo\como testargumento.

    Além do SPC, existem alguns caracteres que sudoescapam. Isso inclui backtick, ;, |, (, ), *, &, =, \mas estranhamente, não $(ou talvez essa seja a única razão de ser dessas -s/ --loginopções: ter um shell expandir variáveis).

    Ele inclui @embora. Se você observar o código , ele escapará de todos os bytes, exceto os alnums ASCII _, -e $.

     if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
       *dst++ = '\\';
    

    Então:

    sudo -s echo '$@'
    

    sudorealmente é executado "$SHELL" -c 'echo $\@'e isso explica por que, no seu exemplo, $@não é expandido pelo shell iniciado, sudo --login mas por aquele que você diz para ele ser executado.

    Na tua

    sudo sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
    

    sudoexecuta rooto shell de login do '( bashno seu caso) e diz para ele interpretar:

    sh -c echo\ \"p0\=$0\"\ \&\&\ echo\ \"p1\=$1\"\ \&\&\ echo\ \"p2\=$2\"\ \&\&\ echo\ \"all\=$\@\" sh 1 2
    

    Os argumentos foram unidos com espaços e todos os caracteres SPC, ", =, &, @mas não $foram escapados. Como aqueles $não foram escapados, o shell de login do bash expandirá $0, $1, $2mas não $\@por causa dessa barra invertida.

    Você pode ver com:

    $ SHELL=echo sudo -s sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
    -c sh -c echo\ \"p0\=$0\"\ \&\&\ echo\ \"p1\=$1\"\ \&\&\ echo\ \"p2\=$2\"\ \&\&\ echo\ \"all\=$\@\" sh 1 2
    

    Para que o shell de login bashacabe sendo executado shcom -co primeiro argumento,

    echo "p0=-bash" && echo "p1=" && echo "p2=" && echo "all=$@"
    

    como segundo argumento e sh, 1, 2como 3º, 4º e 5º.

    Para contornar isso, você pode usar ${0}em vez de $0, porque sudoo transforma para $\{0\}impedir que o shell de login o expanda para o conteúdo de seu $0 :

    $ sudo --login sh -c 'echo "p0=${0}" && echo "p1=${1}" && echo "p2=${2}" && echo "all=${@}"' sh 1 2
    p0=sh
    p1=1
    p2=2
    all=1 2
    

    Edit: a história traz luz à razão por trás disso

    mais descobertas ao olhar para o código. A não fuga de $foi aparentemente introduzida em 2013 por esta mudança . Que se refere ao bug#564 que se refere ao bug#413 .

    Parece que antes que o bug#413 fosse "corrigido" , sudose comportou como eu esperava.

    Aquilo é:

    sudo -i 'some shell code'
    

    O shell de login interpretou esse código de shell (e sudo -s 'some shell code'interpretou $SHELLesse código de shell). Mas a resolução do bug#413 quebrou, porque a pessoa que relatou o bug não entendeu que funcionava dessa maneira. E o bug#564 quebrou ainda mais (em uma tentativa de reverter apenas parte da quebra introduzida pela resolução do bug#413).

    Cheguei a compilar sudo1.7.1 de 2009 e as opções -s/ -iestavam funcionando como eu esperava na época. 1.7.3(com resolução do bug # 413) funcionou como você aparentemente esperava:

    $ sudo-1.7.1 -i 'echo "$SHELL"'
    /bin/bash
    $ sudo-1.7.3 -i 'echo "$SHELL"'
    -bash: echo "$SHELL": command not found
    $ sudo-1.8.21p2 -i 'echo "$SHELL"'
    -bash: echo "/bin/bash": No such file or directory
    
    $ sudo-1.7.3 -i sh -c 'echo "p0=$0" && echo "p1=$1" && echo "p2=$2" && echo "all=$@"' sh 1 2
    p0=sh
    p1=1
    p2=2
    all=1 2
    

    Esse escape introduzido na correção para esse bug#413 é facilmente enganado porque bater a \na frente de todos os bytes (não caractere) não funciona para todos.

    Além do caso óbvio de rconde \nem é um operador de citação, na maioria dos shells, a nova linha não pode ser citada com \:

    $ SHELL=sh sudo -s echo $'a\nb'
    ab
    $ SHELL=csh  sudo -s echo $'a\nb'
    a b
    

    Isso também significa que argumentos vazios são descartados:

    $ sudo printf '<%s>\n' a '' b
    <a>
    <>
    <b>
    $ sudo -s printf '<%s>\n' a '' b
    <a>
    <b>
    

    Além disso, ao inserir um \antes de cada byte , está transformando caracteres em outros em charsets onde o byte 0x5c (a codificação de \) é encontrado em outros caracteres:

    $ SHELL=bash LC_ALL=zh_HK.big5hkscs sudo -s echo $'\xa3``uname`\xa3`'
    bash: line 2: Linuxα: command not found
    α
    

    0xa3 0x60 é grego Epsilon nessa localidade. E sudo muda o 0x60s para 0x5c 0x60 e 0xa3 0x5c é o alfabeto grego, o que explica por que o unamecomando foi executado. sudomudou o

    ε`uname`ε
    

    para

    \α`\`uname\`\α`
    

    E é claro que o comportamento acaba sendo surpreendente, pois os parâmetros posicionais $-, , e (onde é um nome de variável POSIX válido) são expandidos, mas não os outros parâmetros (como aqui, mas também , , , ) ou ou ( / / ) ou ( // ...).$$$varnamevarname$@$!$?$*$#${varname}$var[1]cshtcshzsh$var(1)rces

    • 9

relate perguntas

  • Execute um único comando como outro usuário; restrições ao sudo

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Dividir por delimitador e concatenar problema de string

  • MySQL Select com função IN () com array bash

  • Permitir que o usuário execute um comando como root

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve