Por que o til (~) não se expande entre aspas duplas?

54

De acordo com esta resposta e meu próprio entendimento, o til se expande para o diretório inicial:

$ echo ~
/home/braiam

Agora, sempre que eu quiser que a expansão do shell funcione, ou seja, use nomes de variáveis ​​como $FOOe não quebre caracteres inesperados, espaços, etc., deve-se usar aspas duplas ":

$ FOO="some string with spaces"
$ BAR="echo $FOO"
$ echo $BAR
echo some string with spaces

Por que essa expansão não funciona com o til?

$ echo ~/some/path
/home/braiam/some/path
$ echo "~/some/path"
~/some/path
Braiam
fonte
3
Observe também que isso tem inconsistência ao fornecer um argumento de programa na linha de comando que, no argumento de comando, se --path ~/myfileexpande, mas --path=~/myfilenão.
Ángel
Relacionado: ~ sempre é igual a $ HOME #
Stéphane Chazelas
Uma variação desse tema é unix.stackexchange.com/questions/279565 .
JdeBP

Respostas:

45

O motivo, porque entre aspas duplas, til ~não tem significado especial, é tratado como literal.

O POSIX define aspas duplas como:

Os caracteres entre aspas duplas ("") preservarão o valor literal de todos os caracteres entre aspas duplas, com exceção dos caracteres cifrão, aspas e barra invertida,

...

O aplicativo deve garantir que uma aspas duplas seja precedida por uma barra invertida a ser incluída nas aspas duplas. O parâmetro '@' possui um significado especial entre aspas duplas

Exceto $, `, \e @, outros caracteres são tratados como aspas duplas dentro literais.

cuonglm
fonte
9
Nesse caso, acho que você deve usar $HOME.
Seth
11
Ou você apenas não pode citar o ~, por exemplols -l ~/"My Documents"
Andrew Medico
Isso é muito intuitivo. Qual é a razão pela qual eles escolheram fazer isso? (Esta resposta não realmente dar a razão, mas apenas aponta para o padrão, mas, presumivelmente, o padrão foi escrito assim por um motivo .)
iconoclasta
11
@iconoclast se você realmente quer um "por que eles foram implementados dessa maneira", leia a resposta de Stephane .
Braiam 8/03/15
2
Então, @iconoclast, por que é o céu é azul? :) :) :)
Jesse Chisholm
32

A expansão de til é definida pelo POSIX como:

A "til prefixo" consiste em um unquoted <tilde> caractere no início de uma palavra, seguido por todos os caracteres que precedem o primeiro unquoted <barra> na palavra, ou todos os caracteres da palavra se não houver < barra>. Em uma atribuição, vários prefixos de til podem ser usados: [...] após o <equals-sign> da atribuição, após qualquer <colon> não citado ou ambos. [...] Se nenhum dos caracteres no prefixo til for citado, os caracteres no prefixo til após o <tilde> serão tratados como um possível nome de login no banco de dados do usuário. [...] Se o nome de login for nulo (ou seja, o prefixo til contém apenas o til), o prefixo til é substituído pelo valor da variável HOME. Se HOME não estiver definido, os resultados não serão especificados. [...]

Portanto, a resposta mais curta é "porque é definida dessa maneira": citar qualquer um dos caracteres no prefixo, incluindo o ~, suprime a expansão.

Ele também define a expansão como sempre resultando em uma única palavra; portanto, citar seria desnecessário:

O nome do caminho resultante da expansão do til deve ser tratado como se fosse citado para evitar que seja alterado pela divisão de campos e expansão do nome do caminho.

Onde parte do caminho requer citações, mas o restante é um prefixo de til, você pode combinar a expansão de til e as citações comuns diretamente:

$ cat ~/"file name with spaces"

No "porquê" mais amplo: como não há uso concebível para a divisão de palavras ~, esse deve ser o comportamento padrão, em vez de exigir que seja citado. Como não há necessidade de citá-lo, atribuir ~um significado especial a aspas seria uma complicação desnecessária. E, é claro, razões históricas significam que não poderia ser alterado agora, mesmo que isso fosse desejável.

Michael Homer
fonte
De acordo com este guia do bash , a expansão do til ocorre antes da separação do espaço em branco. Existe uma maneira de fazer com segurança uma expansão de til, mesmo se o diretório inicial tiver espaço em branco? Normalmente, é claro, você faria esse tipo de coisa "".
Lucretiel
A expansão é uma única palavra; veja a segunda passagem citada na resposta.
Michael Homer
23

~ se origina no shell C, muito antes de ter sido adicionado ao shell Korn e posteriormente adicionado à especificação do shell POSIX.

No C-shell, ~havia um operador de globbing (expandido pela mesma rotina que o de expansão, *.txtpor exemplo), assim como o resto do globbing não era realizado entre aspas duplas.

Stéphane Chazelas
fonte
11

Embora isso não responda por que foi projetado dessa maneira, você o utiliza $HOMEse precisar substituí-lo, já que é basicamente ~isso que acontece.

$ echo "$HOME/some/path"
/home/braiam/some/path
combinações
fonte
6
isso não funciona com~otheruser
Johannes Kuhn
2
É verdade, mas você pode fazer: THEM = ~ otheruser, em seguida, use "$ THEM / some / path"
mistura
11
A solução alternativa para ~otherusermostra como foi uma má idéia tratar de forma ~diferente das variáveis ​​e outras coisas que são expandidas entre aspas duplas.
Iconoclast