Fazer cd é basicamente chamar cd sem argumentos e de acordo com o comportamento cd "... se dir não for fornecido, o valor da variável de shell HOME é o padrão." (de manual do bash ). Por contraste, cd ~ é quando você fornece argumentos para o comando cd , que por acaso é ~ e o shell executará expansão do til . Tanto quanto voltar ao diretório home do usuário - não há diferença. Em qualquer um dos casos, a variável de ambiente HOME será consultada:
$ env 'HOME=/usr' bash -c 'cd;pwd; cd ~;pwd'
/usr
/usr
Efetivamente, isso também não tem diferença em relação a cd $HOME . No entanto, enquanto cd fará uma única ação, o til poderá ser usado para executar outras expansões como ~+ para o diretório de trabalho atual.
No entanto, curiosamente, podemos unset HOME para quebrar cd , mas ~ ainda funcionará:
$ bash -c 'cd /usr;unset HOME;cd;pwd;cd ~;pwd'
bash: line 0: cd: HOME not set
/usr
/home/xieerqi
Por quê? Novamente, responda no manual:
If HOME is unset, the home directory of the user executing the shell is substituted instead. Otherwise, the tilde-prefix is replaced with the home directory associated with the specified login name.
Observe que a desativação é diferente de fazer a variável vazia HOME= e tem efeito. A documentação fala especificamente sobre a variável não definida. Tornar variável igual a string vazia tem efeito oposto ao que esperávamos:
bash-4.3$ env 'HOME=' bash -c 'cd /usr;set|grep "^HOME"; stat -c "%F" ~;cd;pwd'
HOME=
stat: cannot stat '': No such file or directory
/usr
Aqui você pode ver que fazer HOME empty string quebra o comportamento til e cd .
Tilde e $HOME têm uma diferença e uma razão diferente para a existência. $HOME é uma variável de shell, que também coincidentemente é uma das variáveis de ambiente - e que está disponível para todos os programas; em C você usaria environ() para acessar isso. Por contraste, tilde é a sintaxe específica do shell que executa a expansão do til, embora você possa usar a função wordexp() para executar uma expansão semelhante à shell ( referência ) em C também.
O motivo pelo qual ~ representa HOME foi respondido em esta pergunta : uma vez o caractere til compartilhou a mesma tecla com HOME no terminal Lear-Siegler ADM-3A. HOME , ao contrário, é uma variável de ambiente que tinha um significado puramente simbólico e nenhuma representação física.
Além disso, o fato de HOME ser uma variável de ambiente nos permite desabilitá-la, já que não podemos definir ~ para outra coisa por meios simples.
# cd ~ will still work, because ~ is blank, so it's same as just cd
$ bash -c 'unset HOME; echo $HOME; cd ~;pwd'
/home/xieerqi
$ env 'HOME=' bash -c 'echo $HOME; cd ~;pwd'
/home/xieerqi
Observe a linha em branco em que o primeiro echo produz a variável não definida, e o fato disso. Por outro lado, não podemos fazer coisas assim para til:
$ bash -c '~=; cd ~;pwd'
bash: ~=: command not found
/home/xieerqi
$ bash -c '~=$'$ env 'HOME=' bash -c 'echo $HOME; stat ~;'
stat: cannot stat '': No such file or directory
'; cd ~;pwd'
bash: ~=bash: command not found
/home/xieerqi
$ bash -c 'unset ~; cd ~;pwd'
bash: line 0: unset: '/home/xieerqi': not a valid identifier
/home/xieerqi
No entanto, a alteração de HOME afeta ~ :
$ bash -c 'cd /etc/;stat -c "%n" ~+'
/etc
Além disso, como ~ também funciona como um caractere de expansão, podemos fazer coisas assim para mostrar o diretório de trabalho atual:
$ bash -c 'cd /etc/;PWD="/usr";stat -c "%n" ~+'
/usr
Considerando que, se quisermos fazer isso por meio de variáveis de ambiente, precisamos de PWD , e HOME permanecerá o mesmo, ou se você fizer coisas como echo $HOME+ - isso é apenas concatenação de strings / variáveis. Mas, novamente, ~+ tira informações de variáveis de ambiente:
$ env 'HOME=/usr' bash -c 'cd;pwd; cd ~;pwd'
/usr
/usr
OBSERVAÇÃO : as expansões ~+ e ~- funcionam em ksh , mas não em dash .
Para responder a algumas das suas perguntas específicas:
Is it something specific to BASH or would they behave differently in another Shell?
Não, isso deve ser um comportamento consistente. ksh , dash e csh - todos se comportam com cd ou cd ~ .
why was the ~ added in the first place then ?
Eu diria conveniência e razões históricas como explicado na resposta vinculada sobre o til. Eventualmente, cresceu para executar mais do que apenas expansão de diretório inicial.