procura um comando no PATH com o mesmo nome do script

3

Por exemplo, meu script é $HOME/bin/sudo . Eu gostaria de procurar por um executável em $PATH com o mesmo nome, sudo , e executá-lo - mas não o script $HOME/bin/sudo em si, caso contrário, eu vou correr em um loop infinito!

EDIT: o ponto disto é que, em alguns casos, eu quero que meus scripts substitutos tenham uma prioridade mais alta do que os comandos normais do sistema, enquanto em outros casos eu quero o oposto. Então eu configurei "$ HOME / bin" como primeiro no PATH, então agora eu posso definir prioridades para cada comando individualmente. Também quero algum tipo de "portabilidade" para que os scripts possam ser executados em sistemas diferentes.

    
por eadmaster 24.10.2014 / 11:53

6 respostas

2

POSIX define a opção -p para o command builtin so ...

  • -p Execute a pesquisa de comandos usando um valor padrão para o PATH que garante a localização de todos os utilitários padrão.

Obtida com as opções -v e -V para a saída (respectivamente) analisável ou amigável para humanos da localização de command , e você pode confiar bastante nela para obter o utilitário pretendido quando você pedir um. Aqui está um pequeno script para demonstrar como funciona:

(   cd ~; mkdir -p bin
    cat >./bin/cat
    chmod +x ./bin/cat
    export "PATH=$HOME/bin:$PATH"
    command -V cat | cat
) <<\NOTCAT
#!/bin/sh
command -p cat
! printf "I'm not REALLY cat, but '%s' is!\n" \
         "$(command -pv cat)"
NOTCAT

OUTPUT

cat is /home/mikeserv/bin/cat
I'm not REALLY cat, but '/bin/cat' is!

As primeiras declarações duplas criam um script executável em ~ / bin / cat. $PATH também é modificado para inserir ~/bin em sua cabeça.

Então, quando eu faço command -V cat | cat command escreve no stdin falso do meu cat . E ainda assim sua saída ainda chega à minha tela. Isso ocorre porque command -p cat obtém a real, independentemente de como eu perdi meu $PATH .

    
por 25.10.2014 / 18:46
4

Não há necessidade de scripts ou funções. Se você simplesmente colocar $HOME/bin last em seu caminho, ele será usado apenas se não houver um nome de comando correspondente em nenhum dos diretórios anteriores no $PATH .

Exemplo:

[jenny@sameen ~]$ export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
[jenny@sameen ~]$ which foo
/usr/bin/which: no foo in (/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin)
[jenny@sameen ~]$ export PATH=$PATH:$HOME/bin
[jenny@sameen ~]$ which foo
~/bin/foo
[jenny@sameen ~]$ sudo cp bin/foo  /usr/local/bin/
[jenny@sameen ~]$ which foo
/usr/local/bin/foo

Se você não confia que pode definir seu próprio $ PATH, para que você ainda queira fazer a verificação no script, veja um exemplo:

#!/bin/bash
export ORIGPATH=$PATH  # to revert the path after checking for the binary
export PATH='echo $PATH |sed -e 's{/home/jenny/bin:{{''

MYNAME='basename $0'

if  which $MYNAME
then
    BINFILE='which $MYNAME'
    export PATH=$ORIGPATH 
    echo "Found $MYNAME in $BINFILE "
    $BINFILE
else
    export PATH=$ORIGPATH
    echo "Here goes the rest of the script"
fi
    
por 24.10.2014 / 12:18
0

Procure o comando com um PATH :

modificado
PATH=$(awk -F: 'sub(FS "'$HOME/bin'","")' <<<"$PATH") which sudo

Por exemplo:

$ which sudo
/usr/local/bin/sudo
$ PATH=$(awk -F: 'sub(FS "/usr/local/bin","")' <<<"$PATH") which sudo
/usr/bin/sudo
    
por 24.10.2014 / 12:07
0

Acabei de encontrar essa alternativa que parece bastante confiável.

EXEPATHSLIST="/usr/bin /usr/sbin /bin /sbin /opt/$1/bin /usr/games /usr/local/bin /usr/local/games /system/bin /system/xbin"
for exepath in $EXEPATHSLIST
do
    if [ -x  $exepath/$1 ]; then
        $exepath/"$@"
        exit $?
    fi
done

# alternative using command
command -p "$@"
_ES=$? ; [ $_ES -ne 127 ] && exit $_ES

# more alternative search methods here
# ...

# else command not found
exit 127
    
por 16.10.2015 / 18:40
-1

Se o seu caminho $ HOME / bin não estiver em $ PATH, você poderá testá-lo com

if [ ! -a $(command -v $(basename $0)) ]; then
        YOUR SCRIPT
else
   echo "$(basename $0 already exists in $PATH"
fi
    
por 24.10.2014 / 15:01
-1

Não sei se entendi bem o que você quer, mas type e which devem ajudar. Por exemplo:

$ type -a sudo
sudo is aliased to '/usr/bin/sudo'
sudo is /home/terdon/scripts/sudo
sudo is /usr/bin/sudo

No exemplo acima, há 3 possíveis sudo s, um é um alias e dois estão no meu $PATH . Você pode simplesmente analisar isso para fazer o que quiser. Se você estiver usando um shell que não tenha o type incorporado, poderá fazer o mesmo com which (embora isso não detecte aliases, mas que não deve ser um problema com scripts shell de qualquer maneira.):

$ which -a sudo
/home/terdon/scripts/sudo
/usr/bin/sudo

Com isso em mente, se seu objetivo é evitar um loop infinito com base no nome do script atual, você pode fazer algo como:

#!/usr/bin/env bash

## Get the name of the matching command from your
## $PATH, excluding the script itself ($0).
com=$(type -a $(basename $0) | grep -v $0 | head -n 1 | awk '{print $NF'})
## Run the command on the arguments passed
$com "$@"

Como @edimaster apontou nos comentários, -a não é definido pelo POSIX, portanto pode não estar presente em todos os sistemas. Uma abordagem mais portável, então, seria pesquisar os diretórios de seu $PATH :

#!/usr/bin/env bash

## Get the name of the matching command from your
## $PATH, excluding the script itself ($0).
com=$(find $(printf "%s" "$PATH" | sed 's/:/ /g') -name $(basename $0) |
      grep -v $0 | head -n 1)
## Run the command on the arguments passed
$com "$@"
    
por 24.10.2014 / 19:40