realpath
e readlink
retorne caminhos absolutos:
+akiva@X230:~$ realpath ZannaIsAwesome
/home/akiva/ZannaIsAwesome
Um caminho como esse é fácil de lidar. No entanto, algo como isso terá alguns problemas:
Por exemplo:
Portanto, um nome como esse precisa ser higienizado para poder alimentá-lo com outros comandos. Um caso de usuário pode ser algo como isto:
+a@X230:~/\e[92mM@r|< $hu+'|'|_e|\|\|0rth [`-_-"]$ bacon=$(realpath pullingATerdon)
+a@X230:~$ vim $bacon
Escusado será dizer vim $bacon
que não funcionará como esperado.
O que posso fazer para limpar esse caminho absoluto para que ele funcione com outros comandos?
command-line
bash
paths
Akiva
fonte
fonte
vim "$bacon"
Respostas:
Como fazer isso corretamente
Primeiro, cite sempre suas variáveis . O que você está tentando fazer funciona bem se você citá-lo corretamente:
Eu mantive o nome de arquivo estranho que você escolheu ( embora eu não tenha idéia de por que você o escolheu ) por uma questão de consistência.
Agora, vamos atribuir o caminho de
pullingATerdon
para uma variável e, em seguida, tentar abrir o arquivo:Isso falha, como esperado. Mas, se agora citamos corretamente:
Funciona como esperado. E sim, você também pode abrir o caminho em um editor (adequado):
emacs "$bacon"
funcionará perfeitamente. OK, assim serávim
e qualquer outra coisa. Sua escolha de editor, apesar de infeliz, não é relevante.Por que o seu falhou
Uma maneira rápida de rastrear o que realmente aconteceu no seu caso é usar
set -x
(desligue-o novamente comset +x
), o que faz com que o shell imprima cada comando que será executado antes de executá-lo. ative as mensagens de depuração do shell comset -x
:Que nos mostra que
ls
foi executado com três argumentos distintos:'/home/terdon/foo/\e[92mM@r|<'
,'+'\''|'\''|_e|\|\|0rth'
e'[`-_-"]/pullingATerdon'
. Isso acontece porque o shell executa divisão de palavras e expansão glob em seqüências de caracteres não citadas. Nesse caso, o problema é a divisão de palavras, uma vez que o shell viu os espaços no caminho e leu cada sequência separada por espaços como um argumento separado.O
mkdir
exemplo é um pouco diferente, mas é porque você está nos mostrando a mensagem de erro da segunda chamada do comando. Eu acho que você tentou uma vez e depois executou uma segunda vez para obter o resultado da sua pergunta. A primeira vez que você o executou, seria assim:Novamente, isso tentará criar três diretórios, não um, por causa da divisão de palavras. Primeiro, ele criou (com sucesso) o diretório
/home/terdon/foo/\e[92mM@r|<
:Em seguida, também com sucesso, criou um diretório chamado
+'|'|_e|\|\|0rth
no seu diretório atual:E, em seguida, tentou criar o diretório
[`-_-"]/pullingATerdon
. Isso falhou porquemkdir
, por padrão, não cria subdiretórios (pode, se você o executar-p
):Como sua string não citada continha a
/
,mkdir
considerou que o caminho de dois diretórios tentou encontrar o principal e falhou.Por isso falhou, mas o que aconteceu é mais complicado. A seqüência de caracteres que você usou na verdade é um glob shell, especificamente uma gama glob , que corresponde a todos os arquivos no diretório atual, cujo nome é um dos 5 caracteres
`
,-
,_
ou"
. Como você não possui esses arquivos no diretório atual, o glob não corresponde a nada e, como é o comportamento padrão no bash, retorna automaticamente:Para esclarecer, eis o que acontece se você fornecer uma glob que corresponda a algo:
O não citado
[p*]
é expandido para a lista de nomes de arquivos correspondentes (apenas um, neste caso) e é para isso que é passadoecho
. Outra razão pela qual você deve citar todas as coisas.Finalmente, o erro real que você mostra é da segunda vez em que você executou o comando e falha na primeira etapa, ao tentar criar
/home/terdon/foo/\e[92mM@r|<
, porque a chamada anterior já havia criado esse diretório.De maneira mais geral, sempre que você estiver trabalhando com nomes de arquivos arbitrários, use sempre shell globs. Coisas assim:
Isso funcionará para qualquer nome de arquivo. Não importa o que aconteça. No nosso exemplo acima, você poderia ter feito:
Qualquer glob que identifique o arquivo de destino exclusivamente fará isso. Dessa forma, você não precisa se preocupar com os caracteres especiais e pode deixar que o shell lide com eles.
Algumas referências úteis:
Como posso encontrar e lidar com segurança com nomes de arquivos contendo novas linhas, espaços ou ambos? : Uma das perguntas frequentes no excelente Wiki de Gray Cat.
Implicações de segurança de se esquecer de citar uma variável nos shells bash / POSIX : o mesmo post que referenciei no início desta resposta. Uma explicação excelente e muito detalhada de todas as coisas que podem dar errado se você não citar corretamente as variáveis do shell.
Por que meu script de shell engasga com espaços em branco ou outros caracteres especiais? : tudo o que você sempre quis saber sobre como lidar com nomes de arquivos arbitrários no shell.
Quando é necessário aspas duplas? : Mais sobre aspas e variáveis e, especificamente, os poucos casos em que você não precisa citá-las
fonte