Estou um pouco surpreso que ninguém tenha mencionado isso ainda, mas você pode usar readlink -f
para converter caminhos relativos em caminhos absolutos e adicioná-los ao PATH como tal.
Por exemplo, para melhorar a resposta de Guillaume Perrault-Archambault,
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
PATH="${PATH:+"$PATH:"}$ARG"
fi
done
}
torna-se
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]
then
if ARGA=$(readlink -f "$ARG") #notice me
then
if [ -d "$ARGA" ] && [[ ":$PATH:" != *":$ARGA:"* ]]
then
PATH="${PATH:+"$PATH:"}$ARGA"
fi
else
PATH="${PATH:+"$PATH:"}$ARG"
fi
fi
done
}
1. O básico - que bem isso faz?
O readlink -f
comando (entre outras coisas) converterá um caminho relativo em um caminho absoluto. Isso permite que você faça algo como
$ cd / caminho / para / meu / bin / dir
$ pathappend .
$ echo "$ PATH"
<your_old_path> : / caminho / para / meu / bin / dir
2. Por que testamos duas vezes o CAMINHO?
Bem, considere o exemplo acima. Se o usuário disser a
partir do diretório uma segunda vez,
será . Claro, não estará presente em . Mas, em seguida, será definido como
(o equivalente caminho absoluto ), que é já . Então, precisamos evitar a adição de uma segunda vez.pathappend .
/path/to/my/bin/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
Talvez o mais importante readlink
seja que, como o nome indica , o objetivo principal é olhar para um link simbólico e ler o nome do caminho que ele contém (ou seja, aponta para). Por exemplo:
$ ls -ld /usr/lib/perl/5.14
-rwxrwxrwx 1 root root Sep 3 2015 /usr/lib/perl/5.14 -> 5.14.2
$ readlink /usr/lib/perl/5.14
5.14.2
$ readlink -f /usr/lib/perl/5.14
/usr/lib/perl/5.14.2
Agora, se você diz pathappend /usr/lib/perl/5.14
, e você já tem /usr/lib/perl/5.14
no seu CAMINHO, tudo bem; podemos simplesmente deixar como está. Mas, se /usr/lib/perl/5.14
já não estiver no seu PATH, chamamos readlink
e obtemos ARGA
= /usr/lib/perl/5.14.2
e, em seguida, adicionamos isso a PATH
. Mas espere um minuto - se você já disse pathappend /usr/lib/perl/5.14
, então você já tem /usr/lib/perl/5.14.2
seu PATH e, novamente, precisamos verificar isso para evitar adicioná-lo a PATH
uma segunda vez.
3. Qual é o problema if ARGA=$(readlink -f "$ARG")
?
Caso não esteja claro, essa linha testa se o resultado readlink
é bem - sucedido. Isso é apenas uma boa prática de programação defensiva. Se vamos usar a saída do comando m
como parte do comando n (onde m < n ), é prudente verificar se o comando m falhou e lidar com isso de alguma forma. Eu não acho que isso readlink
irá falhar - mas, como discutido em Como recuperar o caminho absoluto de um arquivo arbitrário do OS X
e de outros lugares, readlink
é uma invenção do GNU. Ele não está especificado no POSIX, portanto, sua disponibilidade no Mac OS, Solaris e outros Unixes não Linux é questionável. Na verdade, acabei de ler um comentário que diz "readlink -f
parece não funcionar no Mac OS X 10.11.6, mas realpath
funciona imediatamente . ”Portanto, se você estiver em um sistema que não possui readlink
ou onde readlink -f
não funciona, poderá modificá-lo script a ser usado realpath
.) Ao instalar uma rede de segurança, tornamos nosso código um pouco mais portátil.
Claro, se você estiver em um sistema que não possui readlink
(ou realpath
), não vai querer fazer isso .pathappend .
O segundo -d
teste ( [ -d "$ARGA" ]
) é realmente provavelmente desnecessário. Não consigo pensar em nenhum cenário em que $ARG
um diretório seja readlink
bem - sucedido, mas $ARGA
não seja um diretório. Apenas copiei e colei a primeira if
declaração para criar a terceira e deixei o -d
teste por preguiça.
4. Outros comentários?
Sim. Como muitas das outras respostas aqui, esta testa se cada argumento é um diretório, o processa se for e o ignora se não for. Isso pode (ou não) ser adequado se você estiver usando pathappend
apenas .
arquivos " " (como .bash_profile
e .bashrc
) e outros scripts. Mas, como essa resposta mostrou (acima), é perfeitamente viável usá-la interativamente. Você ficará muito confuso se fizer isso
$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found
Você notou que eu disse nysql
no pathappend
comando, em vez de mysql
? E isso pathappend
não disse nada; apenas ignorou silenciosamente o argumento incorreto?
Como eu disse acima, é uma boa prática lidar com erros. Aqui está um exemplo:
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ]
then
if [[ ":$PATH:" != *":$ARG:"* ]]
then
if ARGA=$(readlink -f "$ARG") #notice me
then
if [[ ":$PATH:" != *":$ARGA:"* ]]
then
PATH="${PATH:+"$PATH:"}$ARGA"
fi
else
PATH="${PATH:+"$PATH:"}$ARG"
fi
fi
else
printf "Error: %s is not a directory.\n" "$ARG" >&2
fi
done
}