OBSERVAÇÃO: Todos os exemplos apresentados aqui devem ser executados no diretório em que os arquivos e a lista de nomes de arquivos estão localizados. Por exemplo, se estiverem na pasta /mnt/Hard\ Drive/some\ files/
, assegure-se de que filenames.txt
esteja armazenado lá também. Ao executar os comandos do shell, por favor, cd /mnt/Hard\ Drive/some\ files/
e execute os exemplos.
AWK
A chamada de sistema do AWK pode ser usada com itens que contenham espaços, mas é um pouco complicado. Seu código original tinha alguns erros de sintaxe e cat
inútil. Independentemente desse fato, o caminho apropriado seria o comando ser construído com sprintf()
na variável primeiro e passar essa variável para system()
. Assim:
$ ls dir\ with\ spaces/
$ awk '{cmd=sprintf("fpath=$(realpath -e \"%s\" );%s %s \"$fpath\" \"%s\"",$0,"ln","-s","dir with spaces/");system(cmd) }' filenames.txt
$ ls dir\ with\ spaces/
ascii.txt@ disksinfo.txt@ input.txt@ process info.txt@
BASH (ou qualquer shell parecido com o Bourne)
O caminho da menor resistência seria via script de shell pequeno dado abaixo:
#!/bin/bash
# uncomment set -x for debugging
#set -x
# Preferably, the directory should be full path
dir="dir with spaces/"
while IFS= read -r line
do
if [ "x$line" != "x" ] && [ -e "$line" ];
then
fpath=$( realpath -e "$line" )
ln -s "$fpath" "$dir"
fi
done < filenames.txt
Script em ação:
$ ls -l dir\ with\ spaces/
total 0
$ cat filenames.txt
input.txt
ascii.txt
disksinfo.txt
process info.txt
$ ./makelinks.sh
$ ls -l dir\ with\ spaces/
total 0
lrwxrwxrwx 1 xieerqi xieerqi 9 1月 15 00:47 ascii.txt -> ascii.txt
lrwxrwxrwx 1 xieerqi xieerqi 13 1月 15 00:47 disksinfo.txt -> disksinfo.txt
lrwxrwxrwx 1 xieerqi xieerqi 9 1月 15 00:47 input.txt -> input.txt
lrwxrwxrwx 1 xieerqi xieerqi 16 1月 15 00:47 process info.txt -> process info.txt
A maneira como funciona é simples: while IFS= read -r line; do . . . done < filenames.txt
lê os arquivos de nomes.txt linha por linha, cada vez que a linha entra em line
variable. Verificamos se essa linha não está vazia e se o arquivo existe (esse script deve ser executado no mesmo diretório onde os arquivos originais e a lista de arquivos estão localizados). Se ambas as condições forem verdadeiras, fazemos links.
Note que você deve garantir que o arquivo termine com uma nova linha - se houver uma última linha que não termine com caractere de nova linha (o que acontece), essa linha final será ignorada, portanto, não haverá nenhum link feito para esse arquivo.
Apesar de não ser ideal e não sem peculiaridades, esta é uma solução funcional para casos em que o system()
do awk não está disponível (o que provavelmente é raro hoje em dia).
xargs
Uma abordagem de shell um pouco mais simples seria via xargs
e bash -c '' sh
, onde lemos filenames.txt, novamente, linha por linha com -L1
flag, e usamos cada linha como argumentos para bash. Usando $@
, pegamos toda a matriz de argumentos da linha de comando ($ 1, $ 2, $ 3 ... etc.) e transformamos na variável string, que é então passada para ln
. O sh
no final é definir a variável $0
. É discutível se é necessário fazer, mas esse não é o tópico desta questão, por isso vamos ignorá-lo:)
$ xargs -I {} -L1 bash -c 'file="$@";fpath=$(realpath -e "$file"); ln -s "$fpath" ./dir\ with\ spaces/"$file" ' sh < filenames.txt
$ ls dir\ with\ spaces/
ascii.txt@ disksinfo.txt@ input.txt@ process info.txt@
Python
$ ls dir\ with\ spaces/
$ python -c "import os,sys;fl=[f.strip() for f in sys.stdin];map(lambda x: os.symlink(os.path.realpath(x),'./dir with spaces/' + x),fl)" < filenames.txt
$ ls dir\ with\ spaces/
ascii.txt@ disksinfo.txt@ input.txt@ process info.txt@
A maneira como isso funciona é simples - redirecionamos filenames.txt
para stdin
de python, lemos cada linha na lista fl
e depois executamos os.symlink()
para cada item na lista. Comprimento de uma linha, mas funciona.
Perl
Uma versão mais curta é obtida via Perl:
$ perl -lane 'use Cwd "realpath";symlink(realpath($_),"./dir with spaces/" . $_)' < filenames.txt
$ ls dir\ with\ spaces/
ascii.txt@ disksinfo.txt@ input.txt@ process info.txt@