Confusão de interpolação de variáveis Bash

1

Estou tentando entender a interpolação de variáveis do Bash.

Eu quero usar readlink para mostrar o caminho para o qual um link simbólico aponta.

Se eu usar uma string, funciona.

$ echo "$(readlink -- ~/.gitconfig)"
/Users/jord/.dotfiles/gitconfig

Por alguma razão, não funciona quando tento usar uma variável em vez de uma string.

$ file="~/.gitconfig"
$ echo "$(readlink -- $file)"

Nada é impresso, exceto uma linha em branco.

Se eu fizer a mesma coisa, mas com dirname (como exemplo), a interpolação de variável funciona como eu esperaria.

$ file="~/.gitconfig"
$ echo "$(dirname -- "$file")"
~

O que estou fazendo de errado?

    
por jordelver 26.08.2018 / 19:55

1 resposta

3

~ nas cotações permanece literal ~ . A parte relevante do Manual de Referência de Bash começa com

If a word begins with an unquoted tilde character (~), …

Para ver a diferença, compare:

file="~/.gitconfig"
echo "$file"
file=~/".gitconfig"
echo "$file"

No seu primeiro exemplo, $(…) funciona primeiro e, no contexto, ~ não é citado. Então, ele se expande conforme o esperado.

Seu $file , quando "não funciona", contém literal ~ . O padrão POSIX diz :

The order of word expansion shall be as follows:

Tilde expansion […], parameter expansion […], command substitution […], and arithmetic expansion […] shall be performed, beginning to end. […]

Como a expansão do til é executada antes da expansão do parâmetro, uma variável que se expande para ~/something não se expande ainda mais para um caminho adequado.

Lembre-se de que ~ ou ~/ é especial para o seu shell em algumas circunstâncias, mas para (quase?) qualquer outra ferramenta, não é um caminho válido. Quando funciona, é porque o shell faz sua "mágica" primeiro e a outra ferramenta vê o caminho já expandido (como /Users/jord ).

Note em seu último exemplo que a expansão de til não funciona , você ainda recebe o literal ~ e é muito tarde para o shell fazer algo a respeito sem truques adicionais (como eval ). dirname não reclama porque trabalha com strings. Não importa se o caminho fornecido é válido, existente, etc. Ele basicamente procura apenas o último componente não-barra e descarta-o com barras finais (se houver).

Veja também esta resposta .

    
por 26.08.2018 / 20:11