eval usado com comando canalizado

eval usado com comando canalizado

Eu tenho file.txt com comando armazenado em uma linha (este comando é válido quando executado no console) e quero executá-lo em uma linha com sh like

cat file.txt | eval

O que está faltando? alguma dica?

e se eu tiver um arquivo com muitos comandos (um para cada linha) e quiser executar apenas um comando (uma linha inteira)? minha primeira ideia é:

head -n5 | tail -n1 | eval

Responder1

evalnão lê sua string de comando do stdin.

eval "$(cat file.txt)"
# or easier, in ksh/bash/zsh
eval "$(<file.txt)"
# usually you cannot be sure that a command ends at the end of line 5
eval "$(head -n 5 file.txt)"

Em vez disso, evalvocê pode usar padrão .ou bash/ zsh/ ksh sourcese os comandos estiverem em um arquivo de qualquer maneira:

source ./file

(observe que é importante adicionar isso ./. Caso contrário, sourceprocure filein $PATHantes de considerar o fileno diretório atual. Se estiver no modo POSIX, bashnem consideraria o fileno diretório atual, mesmo que não seja encontrado em $PATH).

Isso não funciona na escolha de uma parte do arquivo, é claro. Isso poderia ser feito por:

head -n 5 file.txt >commands.tmp
source ./commands.tmp

Ou (com ksh93, zsh, bash):

source <(head -n 5 file.txt)

Responder2

então... uma solução para sua pergunta é 100% possível e (no contexto de make) importante.

Encontrei isso com um makefile e, dada a dificuldade de aninhar comandos bash em um makefile que já usa $(...)para chamar variáveis, é bom poder fazer exatamente o que você está perguntando.

Em vez de usar eval, basta usar o comando do sistema awkou :perl

// command_list.sh:
echo "1"
echo "2"
echo "3"

// command line prompt:
$: cat command_list.sh | awk '{system($0)}'
1
2 
3

E, construção de comando:

// a readable version--rather than building up an awk miniprogram, 
// split into logical blocks:

$: cat inputs.txt | awk '{print "building "$1" command "$2" here "}' | awk '{system($0)}' 

Responder3

Tecnicamente, é impossível avaliar algo em seu ambiente atual se você quiser lê-lo em um canal, pois cada comando no pipeline é executado como um processo separado.

No entanto, dependendo do que você está tentando realizar, isso pode não importar. De qualquer forma, aqui está evalo conteúdo de um pipe:

❯ echo echo hi | eval "$(cat -)"
hi

Aqui está um exemplo do problema. Algo como o seguinte não será impresso 1:

❯ echo a=1 | eval "$(cat -)"; echo $a

Teríamos que fazer o seguinte:

❯ echo a=1 | { eval "$(cat -)"; echo $a; }
1

Responder4

Se você não está determinado a usar eval, use sh:

cat file.txt | sh

Sim, ele será executado em uma instância sh separada, mas esse fato é autodocumentado.

E também há while read:

cat file.txt | while read cmd; do eval $cmd; done

Para executar o comando na 5ª linha do arquivo.txt:

sed -n 5p file.txt | sh

(Sei que esta é uma pergunta antiga.)

informação relacionada