Faz ~ sempre igual a $ HOME

37

Eu sei que isso provavelmente já foi perguntado, mas não consegui encontrá-lo com o Google.

Dado

  • Kernel do Linux
  • Nenhuma configuração que altere $ HOME
  • bash

O ~ == $HOME será verdadeiro?

    
por PythonNut 26.07.2014 / 05:02

2 respostas

41

O que é importante entender é que ~ expansion é um recurso do shell (de alguns shells), não é um magic character que significa seu diretório home 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 do comando ser executado.

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

Como ele é amplamente usado em shells, alguns aplicativos que não são shell também o reconhecem como significando o diretório inicial. Esse é o caso de muitos aplicativos em seus arquivos de configuração ou na linha de comando própria ( mutt , slrn , vim ...).

bash especificamente (que é o shell do projeto GNU e amplamente usado em muitos sistemas operacionais baseados em Linux), quando invocado como sh , segue principalmente o Regras POSIX sobre a expansão ~ e, em áreas não especificadas pelo POSIX, se comportam principalmente como o shell Korn (do qual é parte o clone ), embora veja o bug mencionado abaixo.

Enquanto $var é expandido na maioria dos locais (exceto entre aspas simples), ~ expansão, sendo uma reflexão tardia é expandida apenas em algumas condições específicas.

Ele é expandido quando em seu próprio argumento em contextos de lista, em contextos em que uma string é esperada.

Aqui estão alguns exemplos de onde ele foi expandido em bash :

  • cmd arg ~ other arg
  • var=~
  • var=x:~:x (requerido pelo POSIX, usado para variáveis como PATH , MANPATH ...)
  • for i in ~
  • [[ ~ = text ]]
  • [[ text = ~ ]] ( ~ sendo considerado como padrão em ksh , mas não bash ).
  • case ~ in ~) ...
  • ${var#~} (embora não em algumas outras shells)
  • cmd foo=~ (embora não quando invocado como sh , e somente quando o que está à esquerda do = tenha o formato de um nome de variável bash sem aspas)
  • cmd ~/x (requerido pelo POSIX obviamente)
  • cmd ~:x (mas não x:~:x ou x-~-x )
  • a[~]=foo; echo "${a[~]} $((a[~]))" (não em algumas outras shells)

Aqui estão alguns exemplos em que não estão expandidos:

  • echo "~" '~'
  • echo ~@ ~~ (observe também que ~u se 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 --prefix não é um nome de variável válido)
  • cmd "foo"=~ (em bash , por causa das aspas).
  • quando chamado como sh : export "foo"=~ , env JAVA_HOME=~ cmd ...

Quanto ao que é expandido para: ~ sozinho se expande para o conteúdo da variável HOME , 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 desde POSIX deixa esse comportamento indefinido).

Deve-se observar que em bash versões anteriores à 4.0, a expansão de til foi submetida a 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 comuns.

Observe que, como ele é expandido, o mesmo aviso se aplica a outras formas de expansão.

cd ~

Não funciona se $HOME começar com - ou contiver .. componentes. Então, mesmo que seja improvável que faça alguma diferença, estritamente falando, deve-se escrever:

cd -P -- ~

Ou até mesmo:

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

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

cd

(como cd leva você ao seu diretório pessoal sem nenhum argumento)

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

  • ~4 , ~- , ~-2 (com conclusão) usado para expandir os diretórios na sua pilha de diretórios (os lugares com os quais você tem cd ).
  • diretórios nomeados dinâmicos . Você pode definir seu próprio mecanismo para decidir como o ~something está sendo expandido.
por 26.07.2014 / 11:55
25

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

The value of $HOME

então sempre será o mesmo que seja o que for que $HOME é para o shell atual. Existem várias outras expansões de til, como ~user para o diretório pessoal de user , mas um único ~ sem aspas por si só sempre será expandido para "$HOME" .

Observe que o comportamento de ~ e $HOME pode ser diferente em alguns casos: em particular, se $HOME contiver espaços (ou outro IFS caracteres), então $HOME (sem aspas) expandirá para várias palavras, enquanto ~ será sempre um único palavra. ~ expande-se de forma equivalente a "$HOME" (citado).

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

[[ $HOME == ~ ]]

é sempre verdadeiro, porque [[ suprime a divisão de palavras. [[ ~ == $HOME ] pode não ser se HOME tiver caracteres de correspondência de padrões , mas [[ ~ == "$HOME" ]] (ou seja, "$HOME" ) é sempre verdadeiro. Usá-lo entre parêntesis únicos pode ser um erro de sintaxe para valores de HOME contendo espaços ou caracteres especiais. Para qualquer configuração de diretório pessoal razoável, ~ e "$HOME" são iguais e comparados como iguais.

Stéphane Chazelas notou um caso nos comentários em que ~ e $HOME fornecem valores diferentes: se você unset HOME , então quando você usar ~ Bash chamará getpwuid para ler um valor fora do banco de dados de senha. Este caso é excluído por sua condição de não ter nenhuma configuração alterando $HOME , mas vou mencioná-lo aqui para conclusão.

    
por 26.07.2014 / 05:18