Maneira melhor e mais curta de executar um programa se outro não estiver instalado

5

Eu tenho este código:

#!/bin/bash

num=${1:-undefined}
cmd=$(which {banner,echo} | head -n1)

until [[ "$num" =~ ^[0-9]+$ ]]; do 
    read -p "Type a number: " num
done

for ((num;num>=0;num--)); do
   $cmd $num
   sleep 1
done

Mas acho que existe uma maneira melhor de saber se um programa está instalado. Eu tentei isso. No entanto, acho que isso não está claro:

  1. which banner && cmd=banner || cmd=echo
  2. cmd=$(eval 'which '{banner,echo}'||' :)
  3. cmd=$(which {banner,echo} | head -n1)
  4. cmd=$(which banner || which echo)

Eu gosto mais de 3 do que o resto, mas acho que alguém poderia me ajudar a encontrar um bom método para fazer isso. Aceito o uso de type , hash ou command , se necessário.

Este é um desafio de código compacto, então eu quero fazer um oneliner, torná-lo curto e tentar não repetir o nome da variável ou qualquer comando (exceto || , && e assim)

    
por Helio 16.04.2015 / 22:18

2 respostas

9

A abordagem baseada em função resulta no código mais claro. Há pelo menos duas variantes possíveis, a sugerida por FloHe acima, no comentário (que não seria o meu caminho preferido):

function myprint
{
    if type banner >/dev/null
    then  banner "$@"
    else  echo "$@"
    fi
}

myprint "Hello World!"

ou - a variante que prefiro - para usar uma definição de função condicional :

if type banner >/dev/null
then  function myprint { banner "$@" ;}
else  function myprint { echo "$@" ;}
fi

myprint "Hello World!"

que não tem a sobrecarga de uma condição if com cada chamada e que também não requer duplicação de expressões de string ou variável (como em outra sugestão).

    
por 16.04.2015 / 23:21
3

A maneira mais simples é simplesmente executar

command1 "hello world" || command2 "hello world"

Se o primeiro comando não existir, o lado esquerdo do || falhará e o comando à direita será executado. Não vejo por que você precisa testar primeiro. Apenas faça, e se você falhar, faça outra coisa.

Você pode melhorar um pouco ignorando as mensagens de erro causadas por um comando ausente e evitando a repetição da string:

string="Hello world!"
banner "$string" || echo "$string"

Se você realmente precisa verificar a existência de um comando, eu faria assim:

command="banner"
type "$command"  2>/dev/null || command="echo"
"$command" "Hello world!"
    
por 16.04.2015 / 23:13