O que é um ~ (til) quando usado como prefixo de um caminho?

11

Editar: Esta é uma duplicata do /programming/998626/meaning-of-tilde-in-linux-bash-not-home-directory/ . Não tenho reputação de fechar esta pergunta como duplicada.

Não estou me referindo ~como no diretório inicial, mas sim:

$ ls ~foo/bar
/some/mount/point/foo/bar

No entanto, se eu tentar com um ponto de montagem diferente, por exemplo:

$ mount | ag "/dev "
devfs on /dev (devfs, local, nobrowse)
$ ls /dev/stdin
/dev/stdin
$ ls ~stdin
zsh: no such user or named directory: stdin . 
# bash has a similar error message: 
ls: ~stdin: No such file or directory

Como é ~chamado neste contexto? Como funciona?

Editar: Mais informações com base em alguns dos comentários abaixo:

  1. Posso atestar que foonão é um nome de usuário no meu sistema.
  2. Ao tentar concluir automaticamente, ls -lah ~nem todas as opções são mostradas. ou seja, eu consigo cd ~qux, quando quxnão aparece no preenchimento automático. Novamente, quxnão é um usuário no meu sistema.
  3. Se isso importa /some/mount/pointé um compartilhamento de rede.
  4. Todos os detalhes sugerem algum caminho chamado muckery, um recurso de shell Z da expansão do nome do caminho, mas isso também funciona no bash, que aparentemente não suporta coisas como os caminhos nomeados do shell Z.
RD
fonte
5
~fooé o diretório inicial do usuário foo. Se o usuário não for especificado, o usuário atual é o padrão.
DopeGhoti
Mas, neste caso, /some/mount/pointdefinitivamente não é o meu diretório pessoal. cd ~me leva para /Users/$username/--que combina com$HOME
RD RD
1
zshparece também usar o til para indicar diretórios nomeados.
DopeGhoti 13/0218
Eu também suspeitava disso !! Exceto por algum motivo, a série de comandos que publiquei acima também funciona no bash ( bash -c "ls ~foo/bar") - que não possui diretórios nomeados. Além disso, mesmo no zsh, se eu inspecionar o arquivo env, não vejo nenhum diretório nomeado configurado. Eu estou no Mac OS e eu sinto que este é alguma característica específica para OS X.
RD
1
Você apenas disse ~foo. Pegue a string real (não o exemplo foo) e faça grep "actual username" /etc/passwd. ~textdeve funcionar apenas para nomes de usuário de login possíveis, de acordo com o manual do bash (não significa necessariamente que é realmente capaz de efetuar login; no caso de usuários do sistema, como ~lp, por exemplo). Em todos os meus testes, o ~stringcorresponde a stringser nome de usuário.
Sergiy Kolodyazhnyy

Respostas:

14

O que é ~ foo

Citação do manual do bash (com ênfase adicional):

Se uma palavra começar com um caractere de til sem aspas (`~ '), todos os caracteres que precedem a primeira barra sem aspas (ou todos os caracteres, se não houver uma barra sem aspas) serão considerados um prefixo de til. Se nenhum dos caracteres no til-prefix são citados, os caracteres no til-prefix após o til são tratados como um possível nome de login.

~foo expande para fooo diretório inicial do usuário exatamente como especificado em /etc/passwd. Observe que isso pode incluir nomes de usuário do sistema; isso não significa necessariamente usuários humanos ou que eles podem realmente fazer login localmente (eles podem fazer login via chaves SSH, por exemplo).

De fato, conforme observado nos comentários , bashusará a getpwnamfunção Que a função em si é especificado por POSIX padrão, portanto, deve existir em mais Unix-like sistemas, incluindo MacOS X . Essa função não se limita /etc/passwdapenas e pesquisa outros bancos de dados, como LDAP e NIS. Trecho particular do bash código-fonte , tilde.carquivo, começando na linha 394:

  /* No preexpansion hook, or the preexpansion hook failed.  Look in the
     password database. */
  dirname = (char *)NULL;
#if defined (HAVE_GETPWNAM)
  user_entry = getpwnam (username);
#else
  user_entry = 0;

Exemplo prático

Abaixo, você pode ver testes com nomes de usuário do sistema no meu sistema. Preste atenção à passwdentrada e resultado correspondentes dels ~username

$ grep '_apt' /etc/passwd
_apt:x:104:65534::/nonexistent:/bin/false
$ ls ~_apt
ls: cannot access '/nonexistent': No such file or directory
$ grep '^lp' /etc/passwd
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
$ ls ~lp
ls: cannot access '/var/spool/lpd': No such file or directory

Mesmo se, por exemplo, a _aptconta estiver bloqueada, conforme sugerido pela saída, passwd -S aptela ainda será exibida como possível nome de login:

_apt L 11/29/2017 0 99999 7 -1

Observe: Este não é um recurso específico do macOS, mas sim um recurso específico do shell.

Sergiy Kolodyazhnyy
fonte
Duvido que o shell possa descobrir algo sobre a data de validade da conta ou se está bloqueado ou algo ao expandir o til. Por exemplo, no Linux, a data de validade é armazenada /etc/shadow, juntamente com as outras informações de autenticação protegidas, como a senha. A referência em passwdé sobre tornar a senha inválida: isso não impediria a autenticação por outros meios.
22418 ilkkachu
@ilkkachu Sim, você está certo. Eu testei isso adicionando testusere modificando a data de validade da senha. O nome de usuário ainda aparece na conclusão da guia. Eu removi esse pedaço da resposta #
Sergiy Kolodyazhnyy
1
O único problema com esta resposta é que ela cita a bashpágina de manual (e antiga, ao que parece). O OP está realmente usando zsh(poderia ter sido mais claro), embora nos comentários seja mencionado que bashtenha o mesmo comportamento.
Ken Wayne Vanderlinde
2
Você pode usar, em getent passwd foovez de grep foo /etc/passwordseguir os mesmos mecanismos de pesquisa que o shell - talvez incluindo serviços de diretório baseados em rede mencionados pelo @Abigail.
RJHunter
1
Aceito como resposta para o bit 'como LDAP e NIS', que acabou sendo correto no meu caso!
RD
5

Em resumo do motivo pelo qual você está procurando algo ~foo/bar, é porque você tem um usuário nomeado foono sistema com uma pasta nomeada barno diretório inicial.

Veja esta solução em outra comunidade que explica por que (til) ~é mais do que apenas "diretório inicial".

Se você tiver um usuário nomeado binem seu sistema, poderá listar o conteúdo do diretório inicial do bin pelo comando:

ls ~bin

Outra coisa que você pode tentar é usar o preenchimento de tabulação após digitar o seguinte em um prompt (não retorne o carro, basta usar a tecla tab):

ls -lah ~ tab

para ver a lista de diretórios pessoais dos usuários que ~serão expandidos se você continuar. Exemplo (truncado) de saída da conclusão da guia dels -lah ~ tab

$ ls -lah ~ [tab]
~antman/            ~games/
~bin/               ~mail/
WEBjuju
fonte
1
+1 para conclusão da guia. Isso revela claramente todos os nomes de usuário dos quais o bash pode obter os nomes de login possíveis /etc/passwd. Imediatamente ajuda a esclarecer o que está acontecendo se o usuário, obviamente, estiver ciente dos nomes de usuário que possui no sistema.
Sergiy Kolodyazhnyy
2
Obrigado pela dica sobre a conclusão do bash - resultou em alguns resultados interessantes de preenchimento automático. Enquanto ~fooo preenchimento automático, posso atestar que foonão é um usuário no meu sistema (e de fato não existe no /etc/passwd). Além disso, todas as pastas / arquivos /some/mount/pointaparecem no preenchimento automático, o que é super interessante.
RD