Qual é a maneira mais segura (ou mais elegante ou mais curta) de mudar para o diretório de onde um script é chamado?

0

Eu me perguntei o que poderia ser uma maneira segura ou compatível com o Unix de mudar para o diretório a partir do qual um script é chamado.

Estes dois métodos funcionam em um diretório com espaços e caracteres especiais, sem usar aspas. Mas pode haver algumas situações em que isso não funcione. Ou existe?

#!/bin/bash

cd $(dirname $0)
pwd
cd ${0%/*}
pwd

~/test 1"\ ü'\($$ ./cd.sh
/home/syss/test 1"\ ü'\($
/home/syss/test 1"\ ü'\($
    
por syss 07.03.2016 / 20:33

1 resposta

5

Tenha em atenção que $0 pode ser um caminho relativo, pelo que chamar cd duas vezes pode não funcionar. Além disso, extrair a parte do diretório $0 funciona nos casos mais . A maioria não é o mesmo que todos . Alguns casos em que pode falhar incluem:

  • O script não é invocado pela execução de seu caminho, mas chamando um shell, por exemplo bash myscript (que faz uma pesquisa PATH ).
  • O script é movido durante sua execução.

Contanto que você documente que o seu script deve ser chamado sem travessuras, pegar a parte do diretório $0 é ok.

Você precisa ser um pouco cuidadoso; é possível que $0 não contenha uma barra, se ela foi encontrada por meio de uma entrada PATH vazia ou, com algumas conchas, uma entrada PATH para . . Vale a pena dar suporte a este caso, e isso significa que você precisa tomar precauções com ${0%/*} .

A abordagem dirname também não é totalmente direta. A substituição do comando consome novas linhas no final. E com ambas as abordagens, você precisa tomar cuidado para que a string comece com - e seja interpretada como uma opção; passe -- para terminar a lista de opções de um comando.

case "$0" in
  */*) cd -- "${0%/*}";;
  *) cd -- "$0";;
esac

ou

cd -- "$(dirname -- "$0"; echo /)"

Em relação às aspas duplas, você está fazendo a pergunta errada. "$0" é o valor do parâmetro 0 . $0 , sem aspas, é o valor do parâmetro 0 split em caracteres em IFS com cada elemento, em seguida, interpretado como um padrão glob e substituído por arquivos correspondentes, se houver algum (essa última parte apenas se a globulação não estiver desativada) . Você não quer dizer o valor do parâmetro 0 dividido em caracteres em IFS com cada elemento, então interpretado como um padrão glob e substituído por arquivos correspondentes, se houver algum (essa última parte somente se a globulação não estiver desativada) , você? Você quer dizer o valor do parâmetro 0 . Então escreva o que você quer dizer: "$0" .

A única razão pela qual seus testes não engasgaram é que você não tentou com nomes problemáticos e você testou com um shell específico que acontece para reparar seu erro neste cenário específico. Com um nome de diretório como foo bar , você acaba passando dois argumentos foo e bar para o comando cd ; O comando cd do bash interpreta isso como “mude para o diretório obtido pela concatenação de foo , um espaço e bar ”, por isso, é feito o retorno do nome correto. Um shell diferente pode interpretar isso como "reclamar sobre um argumento falso", "alterar para o diretório foo " ou "alterar para o diretório obtido substituindo foo por bar no diretório de trabalho atual". Com o bash, seu script falharia se o nome continha dois espaços consecutivos, por exemplo.

    
por 08.03.2016 / 02:30