O til, `~` é considerado um caminho relativo?

35

Estou tentando extrair a parte diferente do instalador da biblioteca Nvidia cuda. Estou usando o seguinte comando:

mkdir ~/Downloads/nvidia_installers
./cuda_6.5.14_linux_64.run -extract=~/Downloads/nvidia_installers

E recebo a seguinte mensagem:

ERROR: extract: path must be absolute.

E quando eu digito o comando com o endereço literal da minha casa, ele funciona perfeitamente.

./cuda_6.5.14_linux_64.run -extract=/home/likewise-open/XXX/username/Downloads/nvidia_installers

Estou confuso não deveria ser o mesmo de / home / open-da mesma forma / XXX / nome de usuário?

Testado:

./cuda_6.5.14_linux_64.run -extract=$HOME/Downloads/nvidia_installers

e funciona, mas não sei por que não permite ~

Regan
fonte
2
Relacionado: "A 'til prefixo' consiste em um unquoted <tilde> personagem no início de uma palavra, seguido por todos os personagens que precede o primeiro unquoted"
Braiam

Respostas:

47

Bash só expande a ~ se é o começo de uma palavra. Você pode ver isso entre os seguintes comandos:

$ echo -extract=~/test
-extract=~/test

oli@bert:~$ echo -extract ~/test
-extract /home/oli/test

O Bash procura por ~caracteres independentes e ~/por essa substituição. Nenhuma outra combinação ou versão citada funcionará.

$HOMEfunciona porque as substituições de variáveis ​​são mais robustas (esse $é um caractere especial, ~e muito menos):

$ echo Thisisastring${HOME}awrawr
Thisisastring/home/oliawrawr

Enquanto estamos falando ~, ele tem outros usos de substituição:

  • ~+o diretório de trabalho atual (leitura de $PWD)
  • ~-o diretório de trabalho anterior (leitura de $OLDPWD)

Como é óbvio ~, esses podem ter caminhos adicionais alinhados no final e, novamente, esses devem ser o prefixo de uma palavra ou o Bash os ignorará.

Você pode ler mais sobre isso em man bash | less -p ' Tilde'

Oli
fonte
2
Vale a pena notar que zsh não (ou melhor, pode ser configurado para) expandir ~depois =também. Entre outras melhorias convenientes que tem sobre bash.
Jan Hudec
@JanHudec Não - é mais complicado; Não se trata de expandir depois =; trata-se de expandir no início do lado direito de uma atribuição de variável. Isso torna nosso caso um pouco mais confuso quando se olha de perto - veja minha resposta. E zshnão é diferente bashdisso; A descrição para 'zsh' é um pouco enigmática: info --subnodes zsh | less +/'14.7.4 Notes'(páginas man zsh estão faltando)
Volker Siegel
1
@ VolkerSiegel: zshé muito configurável. No meu zsh echo -extract=~/testresulta em -extract=/home/user/test. É ativado por MAGIC_EQUAL_SUBSTopções. Em uma nota lateral, eu tenho todas as páginas de manual do zsh muito bem.
Jan Hudec
@JanHudec Sem dúvida sobre zshser configurável - e outras melhorias; Eu esperava que MAGIC_EQUAL_SUBST (abordado em 14.7.4) esteja desabilitado por padrão e raramente usado; Agora, é obviamente mais relevante se você o tiver ativado em geral. Depois que eu conseguir meu exemplo seção em boa forma, que faria uma boa adição ...
Volker Siegel
@JanHudec Em relação às páginas de manual do zsh, elas estavam ausentes dos pacotes do Ubuntu por um tempo, obrigado pela dica, não sabiam que isso foi corrigido; Olhando para o bug, ele é corrigido para utópico, mas não confiável - isso explica tudo !. ( Barra de lançamento: todas as manpages zsh e arquivos de ajuda em linha estão faltando e AU: Homem zsh faltando ... )
Volker Siegel
19

Apenas consertando

Este comando mostra uma mensagem de erro "ERRO: extração: o caminho deve ser absoluto":

./cuda_6.5.14_linux_64.run -extract=~/Downloads/nvidia_installers

O erro não é útil - o programa já estava muito confuso.
Você já sabe que o erro é do ~, como ele funciona $HOME.

O problema: ~só é substituído no início de uma palavra.

Por exemplo, isso funciona com o til:

echo -extract ~/Downloads

Se você precisar da sintaxe da opção =, usar $ HOME em vez de ~é a solução mais limpa;

echo -extract=$HOME/Downloads

A prática

O que você deveria saber:

Há casos especiais em que ~get é expandido quando não está no início de uma palavra: como parte de uma atribuição de variável, diretamente após o =. O que é confuso aqui, é claro.

O outro caso especial importante é para uso com variáveis ​​como PATH. Nas atribuições de variáveis, ~também é expandido depois :, como após o primeiro =.

$ dir=~ sh -c 'echo D2: $dir'
D2: /home/user
$ sh -c 'echo D2: $dir' dir=~
D2: 
$ echo Dir: $dir
Dir:
$ dir=~; sh -c 'echo D2: $dir'
D2: 
$ echo Dir: $dir
Dir: /home/user
$ sh -c 'echo D2: $dir'; d3=~
D2: 
$ echo d3: $d3
d3: /home/user

O significado do til

Em uma concha, ~o til não é realmente um caminho. Ele é substituído apenas por um caminho $HOME, algumas vezes.

É algo como uma abreviação, ou abreviação, fornecida pelo shell.
Não pode ser usado como um caminho em geral, o shell "expande" para um caminho apenas em locais muito especiais.
E mesmo que seja expandido, pode ser para outra coisa que não o diretório inicial.

  • Ele é expandido apenas no início de uma palavra ou em uma atribuição de variável após um :ou=
  • Só é expandido se não estiver entre aspas
  • Ele é expandido apenas para $HOMEse não houver mais caracteres na palavra antes de um/

O problema na linha de comando

De acordo com isso, o problema em seu comando é que o til em

-extract=~/Downloads/nvidia_installers

não é expandido, porque não é um dos casos listados. Isso é tudo.

A solução poderia ser tornar o til o primeiro caractere não citado de uma palavra, sem outro caractere antes do próximo /- é exatamente isso que você obtém quando usa uma opção com um espaço antes do argumento de opção:

-extract ~/Downloads/nvidia_installers

Outra solução seria usar em seu $HOMElugar. Em um script, essa geralmente é a melhor escolha.

-extract=$HOME/Downloads/nvidia_installers

A mensagem de erro

Mas como a mensagem de erro
"ERROR: extract: path must be absolute."?
encaixar em tudo isso?

Sabemos que o til não foi expandido. Isso significa que o programa recebeu o texto do argumento incluindo o ~, mas sem o /home/ausercomo o caminho. Esse caminho é ~/Downloads/nvidia_installers- mas agora não há concha, então o til não tem significado especial. É apenas um nome de diretório normal. E como todos os outros caminhos do formulário foo/bar/baz, é um caminho relativo

Outros usos

Se houver caracteres após o ~, como em ~alice- com todas as outras regras acima aplicáveis ​​- e houver um nome de usuário alice, que será expandido para o diretório inicial alice, digamos home/alice.
Além disso, se você for bob, ~expandiria para /home/bob, e ~bobexpandiria para o mesmo.

A variante ~+é expandida para o diretório atual,$PWD

Para se referir ao diretório anterior, onde você estava antes do último cd, você pode usar o ~-que é expandido para $OLDPWD.

Se você usar pushde popd, em vez de cd, você já saberá que a pilha de diretórios pode ser acessada como ~-2.

Detalhes

Todos os casos em que ~é expandido para um caminho são manipulados pelo shell . Para outros programas, ~é apenas um caractere de nome de arquivo normal.

Para a definição exata dentro do shell, aqui está a seção relevante da Nota como substituir por é apenas um caso especial de muitos casos: "Se esse nome de login for a cadeia nula, o til será substituído pelo valor do parâmetro do shell HOME. " :man bash
~$HOME

Tilde Expansion
    If a word begins with an unquoted tilde character (`~'), all of the charac‐
    ters  preceding the first unquoted slash (or all characters, if there is no
    unquoted slash) are considered a tilde-prefix.  If none of  the  characters
    in  the tilde-prefix are quoted, the characters in the tilde-prefix follow‐
    ing the tilde are treated as a possible login name.  If this login name  is
    the  null string, the tilde is replaced with the value of the shell parame‐
    ter HOME.  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.

    If the tilde-prefix is a `~+', the value of the shell variable PWD replaces
    the  tilde-prefix.   If  the tilde-prefix is a `~-', the value of the shell
    variable OLDPWD, if it is set, is substituted.  If the characters following
    the tilde in the tilde-prefix consist of a number N, optionally prefixed by
    a `+' or a `-', the tilde-prefix is replaced with the corresponding element
    from  the  directory  stack,  as  it would be displayed by the dirs builtin
    invoked with the tilde-prefix as an argument.  If the characters  following
    the  tilde in the tilde-prefix consist of a number without a leading `+' or
    `-', `+' is assumed.

    If the login name is invalid, or the tilde expansion  fails,  the  word  is
    unchanged.

    Each variable assignment is checked for unquoted tilde-prefixes immediately
    following a : or the first =.  In these cases, tilde expansion is also per‐
    formed.   Consequently, one may use filenames with tildes in assignments to
    PATH, MAILPATH, and CDPATH, and the shell assigns the expanded value.
Volker Siegel
fonte
3

~não é um caminho em si. É um personagem que recebe tratamento especial do shell onde ~ou ~/significa "substituir pelo caminho do diretório inicial do usuário atual". ~usernamesignifica "substituir pelo caminho do diretório inicial do nome de usuário".

Por não ser um caminho, ele é reconhecido apenas em determinados lugares do comando (como o primeiro caractere de um novo token de divisão de espaço).

Quando expandido, ele foi substituído por um caminho absoluto.

O uso do $HOMEworks porque HOME é apenas uma variável definida pelo shell e segue as regras normais do shell para substituição de variáveis ​​(isso acontece antes que a entrada seja dividida em espaços e executada).

Daenyth
fonte
1

Você está certo. ~ / Downloads é o mesmo que / home / nome de usuário / Downloads.

Alguns instaladores e extratores são muito exigentes quanto ao local onde devem colocar as coisas. Eu acho que pode ser porque ele registra os caminhos de arquivos, e os logs não aceitam ~ em um caminho aceito.

Eu apenas me acostumei a digitar / home / nome de usuário. :)

Dan Johansen
fonte