Executa string com variáveis como comando

4

Estou tentando executar uma string no meu script bash. String contém variáveis (para que eu possa substituir alguns argumentos da CLI dependendo das circunstâncias).

O problema é quando eu uso variável contendo --argument=value , tudo quebra, dando erro:

Missing trailing-' in remote-shell command.

Exemplo de código:

#!/bin/bash

rsync_path="/usr/bin/rsync -azhrP"
rsync_ssh_cmd="--rsh='ssh -o Compression=no'"

'$rsync_path /path/to/file $rsync_ssh_cmd username@localhost:/tmp'

Se eu apenas echo a última string deste código, parece bem. Mas, se eu tentar executar essa string a partir do script, ela não será executada conforme o esperado.

Encontrei uma solução - tudo ficou OK se eu tentar

eval "my-command-string"

em vez de

'my-command-string'

ou

(my-command-string)

Por que isso acontece? Como eu poderia (deveria mesmo?) Evitar usar eval ?

Eu uso o bash 4.3.11(1)-release (x86_64-pc-linux-gnu) (Kubuntu 14.04.3).

    
por AntonioK 14.12.2015 / 08:36

2 respostas

5

OK. Você pode evitar usar eval criando algum outro método de avaliar duas vezes sua string. Seja o que for que você faça, você precisa avaliar duas vezes porque sua exigência é analisar uma análise .

O que quero dizer é:

this is 'a parsed" command string"'

^ que funciona para 3 palavras :

1: this 2: is 3: a parsed" command string"

As aspas em 3 não são importantes - elas não são importantes, porque são apenas alguns caracteres em uma palavra . As citações de sintaxe ' usadas na linha de comandos original importaram porque foram interpretadas pelo analisador do shell para delimitar a palavra . Qualquer coisa dentro é apenas parte da palavra.

Então, se você quiser obter mais mais palavras de uma única , pré-analisada palavra, você tem que devolvê-lo ao shell como entrada. É tudo o que existe para isso - o shell processa cotações de entrada na entrada. As aspas são usadas para escapar e delimitar a entrada de formas significativas. Seria bem sem sentido - e bastante assustador - se a concha se mantivesse. Eventualmente, a entrada all será avaliada em nada!

Então você precisa de uma segunda avaliação . Você não pode obter isso de $( substituições de comandos ) porque eles não lidam com entrada , eles lidam com saída . Qualquer efeito colateral de $ palavra-expansão que você possa equiparar à geração de mais palavras não é realmente o caso - isso é campo -splitting. campo -splitando em $IFS e * globbing são executadas pelo shell após entrada palavras já foram delimitados durante o processo de análise.

Agora o objetivo de eval é eval uate como entrada alguma string que o shell já recebeu como entrada. é exatamente a ferramenta certa para isso, mas podemos fazê-lo caso você insista.

Uma maneira é . fornecer sua própria saída.

string="printf '<%s>\n' 'these are' 'some words' 'i will evaluate again'"
. /dev/fd/0 <<!
$string
!

Nesse exemplo, o shell avalia como entrada sua própria saída . Funciona:

<these are>
<some words>
<i will evaluate again>

Você pode fazer isso chamando outro shell para avaliar sua saída como sua entrada:

sh -c "$string"

... a saída é a mesma. Você pode atrasar sua entrada definindo um shell alias :

alias evaled="$string"
evaled

... e novamente, o mesmo resultado.

A maneira mais direta de fazer isso é:

eval "$string"

O efeito é quase o mesmo que em todos os outros exemplos, mas desta vez eu realmente fiz isso com o comando chamado para o que eu pretendia fazer.

eval é um mau rap porque as pessoas não entendem o que faz ou por que o usam de qualquer maneira. O problema é que você não deve usá-lo se não entender os efeitos de fazê-lo. E pode ser fácil perder a noção: o comando é avaliado duas vezes - mais uma vez do que o normal - e o um tempo é geralmente mais do que suficiente para a maioria das pessoas acabar neste site.

Portanto, você deve usar eval neste caso para fazer o que deseja fazer, porque o que você quer fazer é eval uma string. Eu não pretendo julgar por que você deseja eval da string, embora eu espere que possa haver maneiras melhores de fazê-lo, mas quando você quiser que o conteúdo de uma string seja < em> avaliado como entrada do shell, você deve usar eval .

    
por 14.12.2015 / 11:28
1

Você está tendo este problema devido a citações incorporadas: BashFAQ

Este é o trabalho:

#!/bin/bash

rsync_path="/usr/bin/rsync -azhrP"
rsync_ssh_cmd=(--rsh='ssh \-o Compression=no')
'$rsync_path /path/to/file $rsync_ssh_cmd  root@localhost:/tmp'

[PROOF do conceito]

[root@localhost ~]# bash -x  /tmp/c.sh
+ rsync_path='/usr/bin/rsync -azhrP'
+ rsync_ssh_cmd=(--rsh='ssh \-o Compression=no')
++ /usr/bin/rsync -azhrP /path/to/file --rsh=ssh '\-o' Compression=no root@localhost:/tmp
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/root/.ssh/id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
bad permissions: ignore key: /root/.ssh/id_rsa
root@localhost's password:
    
por 14.12.2015 / 09:01

Tags