Talvez eu saiba como readlink
obter arquivos normais do SymLinks. Eu tive essa ideia básica de substituir qualquer SymLink $@
passado para minha função da seguinte maneira:
for file in "$@"; do
[ -L "$file" ] && file=$(readlink -f "$file")
done
O exemplo seria um SymLink /etc/os-release -> ../usr/lib/os-release
.
Mas se eu fizer isso:
set -- '/etc/os-release'; for file in "$@"; do [ -L "$file" ] && file=$(readlink -f "$file"); done; echo "$@"
Ainda consigo o caminho SymLink original, o que é... decepcionante. Eu esperava poder modificar diretamente $@
, se não for possível, existe alguma solução alternativa?
Responder1
Seu código original:
for file in "$@"; do
[ -L "$file" ] && file=$(readlink -f -- "$file")
done
A questão é que a configuração file
no loop não tem consequências para o conteúdo da lista de parâmetros posicionais.
Em vez disso, você pode querer usar
for file in "$@"; do
[ -L "$file" ] && file=$(readlink -f -- "$file")
set -- "$@" "$file"
shift
done
Agora estamos deslocando as entradas do início de "$@"
, uma por uma, e adicionando as entradas possivelmente modificadas ao final da lista. Modificar $@
em um for
loop $@
não é um problema, pois for
os loops sempre iteram em uma lista estática, ou seja, a lista que é iterada é avaliada apenas uma vez no início do loop.
O loop acima, como os abaixo, redefine toda a lista de parâmetros posicionais em cada iteração. Paraenormelista de nomes de arquivos, isso poderá se tornar bastante lento em breve. Se o seu shell tiver matrizes,A resposta de Stephen Kittmostra uma maneira de acelerar isso.
O loop também pode ser escrito em uma forma um pouco mais curta (chamando readlink
cada elemento),
for dummy do
set -- "$@" "$(readlink -f -- "$1")"
shift
done
Isso é usado readlink
de acordo com sua pergunta, mesmo que não seja um utilitário POSIX.
Observe que se a saída dereadlink
termina com uma ou várias novas linhas(ao lado daquele adicionado para encerrar a última linha de saída), eles seriam removidos. Esta é uma consequência da substituição do comando. Se isso for um problema, adicione um caractere final artificialmente na substituição do comando e remova-o, como mosvy
sugerenos comentários:
for file do
[ -L "$file" ] && file=$(readlink -f -- "$file"; echo x)
set -- "$@" "${file%x}"
shift
done
Responder2
Observe que nem readlink
os realpath
comandos POSIX são. O conjunto de ferramentas de linha de comando POSIX não possui realpath()
API semelhante. Aqui, em vez de readlink
(dos quais existem diferentes implementações incompatíveis), você pode usar zsh
which também possui uma realpath()
funcionalidade semelhante a -integrada com seu :P
modificador. No seu sh
roteiro:
eval "set -- $(zsh -c 'print -r ${(qq)argv:P}' zsh "$@")"
Embora você também possa escrever seu script em zsh
primeiro lugar, onde seria apenas:
argv=($argv:P)
Ou se python3
é mais provável que esteja disponível que zsh:
eval "set -- $(
LC_ALL=C python3 -c '
import sys, os, shlex
print(" ".join(map(shlex.quote, map(os.path.realpath, sys.argv[1:]))))' "$@")"