Gerar vários links simbólicos enquanto mantém a estrutura de diretórios

2

Eu quero gerar links simbólicos de várias pastas, mantendo a estrutura de diretórios. Eu li algumas respostas e a melhor coisa que posso fazer agora é:

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f -exec ln -sf \{\} . \;

Isso gera links simbólicos todos no mesmo diretório. Mas o que eu quero é ter a mesma estrutura de diretório que no comando find e, se possível, usar a mesma estrutura da entrada. Por exemplo: input/*/Clean_data/*/*/*.fq.gz

Quando arquivos e diretórios são combinados, o link simbólico deve seguir a mesma estrutura que o link absoluto encontrado com o comando find .

Qualquer entrada é apreciada.

    
por Sander Van der Zeeuw 10.06.2014 / 10:16

4 respostas

2

Eu deveria gerar os comandos com awk e depois canalizá-los para bash :

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f | \
awk '{printf "mkdir -p 'dirname %s'\nln -s %s ./%s \n", substr($0, 27), $0, substr($0, 27)}'

Isso gera uma lista dos comandos, primeiro eu os controlaria e finalmente canalizaria para bash . O comando completo seria:

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f | \
awk '{printf "mkdir -p 'dirname %s'\nln -s %s ./%s \n", substr($0, 27), $0, substr($0, 27)}' | bash
    
por 10.06.2014 / 11:27
4

Feio e frágil, mas deve fazer o trabalho:

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f -print0 | \
  xargs -0 -n 1 \
    sh -c 'mkdir -p "$PWD/'dirname $0'"; ln -s "$0" "$PWD/'dirname $0'"'

Inspirado pela resposta do caos , eu criei esta alternativa que também apara diretórios desnecessários :

find /data/DIV5/SASC/e042_ctcl/input/*/Clean_data/*/*/*.fq.gz -type f   \
     -printf 'mkdir -p "${PWD}/%h"; ln -s "%p" \\n\t"${PWD}/%h"\n'   | \
sed 's#/data/DIV5/SASC/e042_ctcl##'                                   | \
sh -

Ele gera os comandos mkdir e ln necessários:

mkdir -p "${PWD}//data/DIV5/SASC/e042_ctcl/input/x/Clean_data/0/a"; ln -s "/data/DIV5/SASC/e042_ctcl/input/x/Clean_data/0/a/foobar.fq.gz" \
    "${PWD}//data/DIV5/SASC/e042_ctcl/input/x/Clean_data/0/a"

Em seguida, ele remove os diretórios desnecessários deles com sed , resultando em:

mkdir -p "${PWD}//input/x/Clean_data/0/a"; ln -s "/data/DIV5/SASC/e042_ctcl/input/x/Clean_data/0/a/foobar.fq.gz" \
    "${PWD}//input/x/Clean_data/0/a"

O comando ln inicia na mesma linha que mkdir e continua na próxima linha para manter a fonte intacta enquanto corta o destino. Imprimi-los na mesma linha ou em cada linha distinta exigiria um script sed mais complicado.

Explicação da documentação para encontrar , dos parâmetros -printf :

%p File's name (not the absolute path name, but the name of the file as it was encountered by find - that is, as a relative path from one of the starting points).

%h Leading directories of file's name (all but the last element and the slash before it). If the file's name contains no slashes (for example because it was named on the command line and is in the current working directory), then “%h” expands to “.”. This prevents “%h/%f” expanding to “/foo”, which would be surprising and probably not desirable.

    
por 10.06.2014 / 11:20
2

Estou com a impressão de que você está procurando por uma ferramenta como o GNU Stow .

GNU Stow is a symlink farm manager which takes distinct packages of software and/or data located in separate directories on the filesystem, and makes them appear to be installed in the same place. For example, /usr/local/bin could contain symlinks to files within /usr/local/stow/emacs/bin, /usr/local/stow/perl/bin etc., and likewise recursively for any other subdirectories such as .../share, .../man, and so on.

Check it out, se coincide com o caso de uso.

    
por 10.06.2014 / 14:13
1

O Zsh tem uma função conveniente zmv . Primeiro, carregue-o (você pode fazer isso a partir de seu .zshrc ou na linha de comando para um uso de uma sessão):

autoload -U zmv
alias zcp='zmv -C'
alias zln='zmv -L'

Recriar uma floresta de links simbólicos é tão fácil quanto isto:

 zln -s '/data/DIV5/SASC/e042_ctcl/(input/*/Clean_data/*/*/*.fq.gz)' '$1'

Se você quiser percorrer Clean_data diretórios de forma recursiva, em vez de seguir exatamente dois níveis:

 zln -s '/data/DIV5/SASC/e042_ctcl/(input/*/Clean_data/**/*.fq.gz)' '$1'

Há uma grande limitação: isso não criará os subdiretórios necessários. Você pode fazer isso definindo e usando uma função de wrapper para ln que cria diretórios conforme necessário.

ln_s_mkdir () {
  mkdir -p -- ${(P)#}
  ln -s "$@"
}
 zmv -p ln_s_mkdir '/data/DIV5/SASC/e042_ctcl/(input/*/Clean_data/**/*.fq.gz)' '$1'

Você pode fazer o comando funcionar um pouco mais rápido usando interno% co_de do zsh Comandos% e mkdir (que não são carregados por padrão porque têm menos opções que os utilitários GNU encontrados na maioria dos sistemas).

zmodload -F zsh/files b:zf_ln b:zf_mkdir
ln_s_mkdir () {
  zf_mkdir -p -- ${(P)#}
  zf_ln -s "$@"
}
 zmv -p ln_s_mkdir '/data/DIV5/SASC/e042_ctcl/(input/*/Clean_data/**/*.fq.gz)' '$1'
    
por 11.06.2014 / 02:22