~ Sempre é igual a $ HOME

40

Sei que isso provavelmente já foi solicitado antes, mas não consegui encontrá-lo no Google.

Dado

  • Kernel do Linux
  • Nenhuma configuração que altera $ HOME
  • bater

Será ~ == $HOMEverdade?

PythonNut
fonte
3
Acredito que sim, mas esse não é um problema específico do Linux. Em vez disso, acredito ~que será equivalente a $HOMEqualquer ambiente POSIX; mas eu posso estar errado.
HalosGhost
4
Apesar das respostas abaixo ... nem sempre. Compare echo "~"e echo "$HOME".
Sparhawk
@ Sparhawk Espere, então 1 + 1 não é 2? É uma conspiração! O governo está escondendo algo de nós! : P
Doorknob
11
@ Sparhawk, você notará que o OP realmente não citou o ~ou $HOME. : P
HalosGhost
2
@HalosGhost Ah, bom ponto. (Além disso, notei mais tarde que a resposta de Michael Homer menciona "um único não citado ~".) De qualquer forma, algo a ter em mente para o leitor casual, como eu.
Sparhawk

Respostas:

46

O que é importante entender é que a ~expansão é um recurso do shell (de alguns shells), não é um personagem mágico do que significa o diretório inicial onde quer que seja usado.

Ele é expandido (pelo shell, que é um aplicativo usado para interpretar linhas de comando), como $varé expandido para seu valor sob algumas condições, quando usado em uma linha de comando do shell antes que o comando seja executado.

Esse recurso apareceu pela primeira vez no shell C no final da década de 1970 (o shell Bourne não o possuía, nem seu antecessor, o shell Thompson), mais tarde foi adicionado ao shell Korn (um shell mais novo construído sobre o shell Bourne no anos 80). Ele acabou sendo padronizado pelo POSIX e agora está disponível na maioria dos shells, incluindo os que não são do POSIX fish.

Como ele é amplamente utilizado em shells, alguns aplicativos não-shell também o reconhecem como significando o diretório inicial. Esse é o caso de muitas aplicações em seus arquivos de configuração ou a sua própria linha de comando ( mutt, slrn, vim...).

bashespecificamente (que é o shell do projeto GNU e amplamente usado em muitos sistemas operacionais baseados em Linux), quando chamado sh, segue principalmente as regras do POSIX sobre ~expansão, e em áreas não especificadas pelo POSIX, se comporta principalmente como o shell Korn (de que é um clone parcial).

Embora $varseja expandido na maioria dos lugares (exceto dentro de aspas simples), a ~expansão, sendo uma reflexão tardia, é expandida apenas em algumas condições específicas.

Ele é expandido quando por seu próprio argumento em contextos de lista, em contextos em que uma sequência é esperada.

Aqui estão alguns exemplos de onde é expandida bash:

  • cmd arg ~ other arg
  • var=~
  • var=x:~:x(exigido pelo POSIX, usado para variáveis ​​como PATH, MANPATH...)
  • for i in ~
  • [[ ~ = text ]]
  • [[ text = ~ ]](a expansão de ~ser tomada como padrão na AT&T, kshmas não bashdesde a versão 4.0).
  • case ~ in ~) ...
  • ${var#~} (embora não em outras conchas)
  • cmd foo=~(embora não quando invocado como she apenas quando o que está à esquerda da =figura tiver o formato de um bashnome de variável não citado )
  • cmd ~/x (exigido pelo POSIX obviamente)
  • cmd ~:x(mas não x:~:xou x-~-x)
  • a[~]=foo; echo "${a[~]} $((a[~]))" (não em outras conchas)

Aqui estão alguns exemplos em que não é expandido:

  • echo "~" '~'
  • echo ~@ ~~(observe também que ~use destina a expandir para o diretório inicial do usuário u).
  • echo @~
  • (( HOME == ~ )), $(( var + ~ ))
  • com extglob: case $var in @(~|other))...(embora case $var in ~|other)esteja OK).
  • ./configure --prefix=~(como --prefixnão é um nome de variável válido)
  • cmd "foo"=~(em bash, por causa das aspas).
  • quando invocado como sh: export "foo"=~, env JAVA_HOME=~ cmd...

Quanto ao que ele se expande: ~expande sozinho para o conteúdo da HOMEvariável, ou quando não está definido, para o diretório inicial do usuário atual no banco de dados da conta (como uma extensão, pois o POSIX deixa esse comportamento indefinido).

Deve-se notar que no ksh88 e nas bashversões anteriores à 4.0, a expansão do til passou por globbing (geração de nome de arquivo) em contextos de lista:

$ bash -c 'echo "$HOME"'
/home/***stephane***
$ bash -c 'echo ~'
/home/***stephane*** /home/stephane
$ bash -c 'echo "~"'
~

Isso não deve ser um problema em casos habituais.

Observe que, por ser expandido, o mesmo aviso se aplica a outras formas de expansão.

cd ~

Não funciona se $HOMEcomeça com -ou contém ..componentes. Portanto, mesmo que seja pouco provável que faça alguma diferença, estritamente falando, deve-se escrever:

cd -P -- ~

Ou até:

case ~ in
  (/*) cd -P ~;;
  (*) d=~; cd -P "./$d";;
esac

(para cobrir valores de $HOMElike -, +2...) ou simplesmente:

cd

(o cdleva ao seu diretório pessoal sem nenhum argumento)

Outras conchas têm ~expansões mais avançadas . Por exemplo, em zsh, temos:

  • ~4, ~-, ~-2(Com conclusão) usado para expandir os diretórios em sua pilha de diretórios (os lugares que você cdpara antes).
  • diretórios nomeados dinâmicos . Você pode definir seu próprio mecanismo para decidir como ~somethingestá sendo expandido.
Stéphane Chazelas
fonte
25

Em qualquer versão do Bash em qualquer sistema, sim . ~como um termo por si só, é definido para expandir para:

O valor de $ HOME

portanto, sempre será o mesmo que o que $HOMEestá no shell atual. Existem várias outras expansões de til, como ~userpara usero diretório inicial de um arquivo, mas um único sem aspas ~sempre será expandido para "$HOME".

Observe que o comportamento de ~e $HOMEpode ser diferente em alguns casos: em particular, se $HOMEcontiver espaços (ou outros caracteres IFS ), $HOME(sem aspas) será expandido para várias palavras, enquanto ~é sempre uma única palavra. ~expande-se equivalentemente a "$HOME"(entre aspas).

Em relação à sua pergunta específica:

[[ $HOME == ~ ]]

é sempre verdade, porque [[ suprime a divisão de palavras. [[ ~ == $HOME ]pode não ser se HOMEpossui caracteres de correspondência de padrão , mas [[ ~ == "$HOME" ]](ou seja, citado "$HOME") é sempre verdadeiro. Usá-lo entre colchetes simples pode ser um erro de sintaxe para valores de HOMEespaços ou caracteres especiais. Para qualquer configuração diretório home sensata ~e "$HOME"são os mesmos e são considerados iguais.


Stéphane Chazelas observou um caso nos comentários onde ~e $HOMEdão valores diferentes: se você unset HOME, em seguida, quando você usa ~Bash vai chamar getpwuidpara ler um valor do banco de dados senha. Este caso é excluído por sua condição de não haver alteração na configuração $HOME, mas vou mencioná-lo aqui por completo.

Michael Homer
fonte
11
No entanto, /bin/shpode não ser bash. Não tenho certeza de que a shespecificação Posix fala sobre~
Basile Starynkevitch
11
POSIX especifica ~. ~não estava na casca de Thomson ou Bourne (que na época estavam disponíveis como /bin/sh). Não é em rcou seus derivados (onde é usado para outra coisa)
Stéphane Chazelas
5
Em alguns shells bash, incluindo , se HOMEnão estiver definido, se ~expande para o diretório inicial do usuário a partir do banco de dados passwd. Portanto, esse é um caso em que ~pode não se expandir para o valor de $HOME.
Stéphane Chazelas
11
Observe que bashantes do bash4 era usado globbing na expansão de til (tentativa HOME='/*' bash -c 'echo /*'). Então HOME=/*; [ "$HOME" = ~ ], retornaria um erro lá.
Stéphane Chazelas
4
@cuonglm Eu verifiquei o código fonte. Em última análise , chama get_current_user_info , que usa getpwuidem todas as plataformas, exceto Tandem .
Michael Homer