Adicione argumentos ao 'bash -c'


22

Digamos que eu queira executar um comando através do Bash assim:

/bin/bash -c "ls -l"

De acordo com a página de manual do Bash, eu também poderia executá-lo assim:

#               don't process arguments after this one
#               |   pass all unprocessed arguments to command
#               |   |
#               V   V
/bin/bash -c ls -- -l

exceto que não parece funcionar (parece ignorado). Estou fazendo algo errado ou estou interpretando a página de manual errada?

Citações relevantes do homem:

Se a opção -c estiver presente, os comandos serão lidos da sequência. Se houver argumentos após a sequência, eles serão atribuídos aos parâmetros posicionais, começando com $ 0.

e

A - sinaliza o fim das opções e desativa o processamento adicional das opções. Quaisquer argumentos após o - são tratados como nomes de arquivos e argumentos.

Respostas:


33

Você está interpretando a página de manual errada. Em primeiro lugar, a parte de --sinalizar o fim das opções é irrelevante para o que você está tentando fazer. Ele -csubstitui o restante da linha de comando a partir desse ponto, para que ele não passe mais pelo manuseio de opções do bash, o que significa que --ele seria passado para o comando, não tratado pelo bash como um marcador de fim de opções.

O segundo erro é que argumentos extras são atribuídos como parâmetros posicionais ao processo do shell iniciado, e não passados ​​como argumentos ao comando. Então, o que você está tentando fazer pode ser feito como um dos seguintes:

/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar

No primeiro caso, passar ecoar os parâmetros $0e $1explicitamente, e no segundo caso, usar "$@"para expandir como normal como "todos os parâmetros posicionais, exceto $ 0". Observe que, nesse caso, temos que passar algo para ser usado $0também; Eu escolhi "bash", pois é o $0que normalmente seria, mas qualquer outra coisa funcionaria.

Quanto à razão que é feito desta forma, em vez de apenas passar quaisquer argumentos que dão diretamente para o comando que você listar: nota que a documentação diz "comando s são lidos da cadeia", plural. Em outras palavras, esse esquema permite que você faça:

/bin/bash -c 'mkdir "$1"; cd "$1"; touch "$2"' bash dir file

Porém, observe que uma maneira melhor de atingir seu objetivo original pode ser usar, em envvez de bash:

/usr/bin/env -- "ls" "-l"

Se você não precisar de nenhum dos recursos que um shell está fornecendo, não há motivo para usá-lo - envnesse caso, será mais rápido, mais simples e com menos digitação. E você não precisa pensar muito para garantir que ele manipule com segurança nomes de arquivos contendo metacaracteres de shell ou espaços em branco.


3

Não sei ao certo qual é seu objetivo, mas se você está simplesmente tentando construir uma máquina Rube Goldberg - “uma engenhoca, invenção, dispositivo ou aparelho deliberadamente superdimensionado ou exagerado para executar uma tarefa muito simples de uma maneira muito moda complicada "- tente

sh -c 'ls $0' -l

ou

sh -c 'ls $1' supercalifragilisticexpialidocious -l

ou mesmo

sh -c 'ls -$0' l

Você deve entender como isso funciona com a resposta de godlygeek.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.