Evalute passado em variável no bash

1

Existe uma maneira de passar uma variável como um argumento para um script bash e tê-la avaliada no escopo do script?

Fornecido :

# cat /path/to/file/of/host/names
bob
tom
joe
etc...


# dofor
FILE=$1
shift
CMD=$*

while read host; do
    # recursively turns "ssh \$host hostname" from $@ into:
    # ssh bob hostname
    # ssh tom hostname
    # ssh joe hostname
    # etc...
    eval $CMD
done < $FILE

Quando :

# dofor /path/to/file/of/host/names "ssh \$host hostname"

Então : Eu recebo a saída da execução de ssh host hostname para cada nome de host listado em / path / to / file / of / host / names. por exemplo:

bob.example.com
tom.example.com
joe.example.com
etc...
    
por frogstarr78 06.10.2011 / 15:50

3 respostas

1

Você pode usar

#!/bin/bash
FILE=$1
exec 3<$FILE
while read -u 3 host; do
    $2 $host $3
done

Então, se você tiver:

$ cat /tmp/hostnames
some.host1.com
another.host2.net
some.host3.org    
some.host4.com

e execute dofor.sh /tmp/hostnames ssh ls , ele será executado em sequência:

ssh some.host1.com ls
ssh another.host2.net ls
ssh some.host3.org ls
ssh some.host4.com ls

EDIT1:

Se você quiser alterar ssh ou ls em alguns comandos mais longos (ou partes deles), basta usar aspas:

dofor.sh /tmp/hostnames "ssh -p 23" "ls -lh /"

EDIT2:

Com o script a seguir, você poderá usar a variável $host em quantos lugares desejar, em seu comando:

#!/bin/bash
exec 3<$1
while read -u 3 host; do
    eval $2
done

(Eu fiz este mais curto - sem introdução inútil da variável $FILE .) A parte importante aqui é que você precisa usar aspas simples ao redor do comando que contém a variável $ host:

 dofor.sh /tmp/hostnames 'echo "trying $host :"; ssh -p 23 myuser@$host "ls -lh /"'

Mas cuidado que é perigoso usar eval (veja parede do l0b0 ) porque se o arquivo /tmp/hostnames continha um comando em alguma linha, ele seria executado. Melhor não usar isso como root !

    
por 06.10.2011 / 20:36
2

Tente isto:

#!/bin/bash

FILE=$1
shift
CMD=$*
cmds=""

source <({
cat $FILE | while read host; do
    echo $CMD | sed -e "s|\$host|$host|g"
done
})
    
por 06.10.2011 / 16:02
1

Isso deve funcionar, mas é uma má idéia realmente , a menos que você controle completamente o conteúdo de $FILE e contém apenas instruções muito simples.

while read -r
do
    $REPLY
done < $FILE

Para o exemplo SSH, você poderia fazer algo muito mais simples apenas passando os nomes de host:

while read -r host
do
    echo -n "${host}:"
    ssh "$host" hostname
done 9< "$FILE"

Isso deve retornar uma lista de my hostname:remote hostname entradas.

Se você tiver um arquivo com comandos reais, é necessário certificar-se de que o espaço em branco seja manipulado corretamente. A única maneira de ser capaz de lidar com qualquer qualquer parâmetro (incluindo por exemplo echo comandos onde os parâmetros são várias linhas) seria usar um formato personalizado. Uma maneira relativamente simples seria separar cada comando e argumento com um caractere, e colocar um caractere extra between entre o último argumento de um comando e o próximo comando.

    
por 06.10.2011 / 16:00