O script Bash não consegue encontrar o comando se for citado

3

Eu tenho um script bash para executar um comando em vários diretórios. Isso funciona bem quando chamado assim:

$ ./run git status

No entanto, ao citar o subcomando, recebo erros 'Comando não encontrado'.

$ ./run "git status"

Isso me limita a somente ser capaz de passar um comando para ser executado, ao contrário do ideal, por exemplo:

$ ./run "git status && npm install"

executar

#!/bin/bash

paths="/Users/guy/project /Users/guy/project-2"

for i in $paths; do
    (cd "$i" && "$@")
done
    
por Guy 14.09.2017 / 17:05

1 resposta

6

Seu comando run provavelmente espera que um comando seja executado em oposição ao código shell a ser avaliado (edite agora que você o publicou: sim, isso é "$@" )

Se o comando run for realmente um script de shell, ele poderá aceitar comandos internos como eval (editar: sim, funciona), caso em que você deve ser capaz de fazer:

./run eval 'git status && npm install'

(esse código seria avaliado no contexto do script run , que poderia ter efeitos inesperados se modificasse algumas variáveis internas do script, por exemplo (como ./run eval 'PATH=/none; ...' ) (editar: não aqui, pois é o último comando) executado em um subshell)).

Se não, você sempre pode dizer para executar um shell para avaliar o código do shell:

./run sh -c 'git status && npm install'

Aqui, eu também usaria uma variável array para armazenar uma lista de caminhos ao invés de armazená-la em uma variável escalar e contar com o operador split + glob para dividi-la. Você também pode querer relatar falhas no status de saída

#!/bin/bash -
paths=(/Users/guy/project /Users/guy/project-2)
ret=0

for i in "${paths[@]}"; do
  (cd -P -- "$i" && "$@") || ret=$?
done
exit "$ret"

Se você quisesse que seu script aceitasse o código shell, você faria:

#!/bin/bash -
paths=(/Users/guy/project /Users/guy/project-2)
ret=0

for i in "${paths[@]}"; do
  (cd -P -- "$i" && eval "$@") || ret=$?
done
exit "$ret"

Mas aconselho a não fazê-lo, pois o usuário pode ficar tentado a fazer coisas como:

./run git add "$file"

que seria uma vulnerabilidade de injeção de comando oculta (como quando $file é foo;reboot ).

./run eval "git add $file"

seria a mesma vulnerabilidade de injeção de comando, mas pelo menos não estaria oculta para o usuário.

Para que não seja uma vulnerabilidade de injeção de comando, com a variante de run não usando eval :

./run git add "$file"

ou usando eval , mas com código estático e passando o valor dinâmico por meio de uma variável de ambiente.

FILE=$file ./run eval 'git add "$FILE" && git commit -m blah'

ou usando sh -c , mas com código estático e passando o valor dinâmico por meio de um argumento.

./run sh -c 'git add "$1" && git commit -m blah' sh "$file"
    
por 14.09.2017 / 17:11

Tags