Crie cópias de diretório usando find

3

Eu tenho um diretório com vários subdiretórios. Assim

/usr/local/src/ccl/ccl-1.8/x86-headers$ ls
elf  gl  gmp  gnome2  gtk2  jni  libc

Cada um desses diretórios tem um subdiretório adicional C dentro dele, que contém um arquivo populate.sh . Eu quero criar um grupo paralelo de subdiretórios com a mesma estrutura, mas com um valor aleatório acrescentado ao nome do diretório (o valor aleatório deve ser o mesmo em todos os casos) e contendo apenas o subdiretório C com o arquivo populate.sh . Esses diretórios contêm outros arquivos além do arquivo populate.sh .

Isto é para um makefile, portanto, a simplicidade provavelmente deve usar utilitários unix padrão. Estou pensando em encontrar com o -exec flag, ou possivelmente xargs funcionaria, mas estou tendo problemas para entender a documentação, e tenho pouca experiência com scripts de shell. O Perl pode funcionar, mas eu não o usei e prefiro não usá-lo aqui.

Estou usando algo como mktemp -u --tmpdir=. para gerar uma string aleatória no passado, mas dificilmente é ideal, por isso estou aberto a outras sugestões. Idealmente, gostaria de um nome que pareça libc.tmp_xw3st . Ie. tmp_ seguido por uma sequência alfanumérica de 5 dígitos.

Até agora, tenho uma maneira de obter uma listagem dos diretórios de nível superior. : -)

find . -maxdepth 1 -type d -print0

../gmp./jni./gl./elf./libc./gtk2./gnome2

Uma lista de diretórios mais completa está no final desta postagem. Para resumir, quero criar diretórios adicionais, como x86-headers/libc.tmpvalue , que contém apenas o arquivo adicional x86-headers/libc.tmpvalue/C/populate.sh .

Um esboço de uma possível abordagem é lidar com isso em duas etapas, como segue:

Etapa 1: execute a lista de diretórios de nível superior usando find e crie uma estrutura de diretório correspondente, por exemplo, dirname.tmpvalue/C/ usando exec ou canalizando para xargs e usando mkdir -p .

Etapa 2: execute novamente a lista de diretórios de nível superior e cp populate.sh nos subdiretórios C . Isso é um pouco desleixado, porque a lista de diretórios, em teoria, poderia ter sido alterada entre as duas invocações de find , mas isso não é um problema neste caso.

/usr/local/src/ccl/ccl-1.8/x86-headers$ ls -laR

[...]

./jni:
total 96
drwxr-sr-x 3 faheem staff  4096 Jul 31 00:53 .
drwxr-sr-x 9 faheem staff  4096 Jul 31 00:53 ..
drwxr-sr-x 2 faheem staff  4096 Jul 31 00:53 C
-rw-r--r-- 1 faheem staff 19535 Jul 31 00:53 constants.cdb
[more .cdb files]

./jni/C:
total 12
drwxr-sr-x 2 faheem staff 4096 Jul 31 00:53 .
drwxr-sr-x 3 faheem staff 4096 Jul 31 00:53 ..
-rw-r--r-- 1 faheem staff  148 Jul 31 00:53 populate.sh

./libc:
total 1276
drwxr-sr-x 3 faheem staff   4096 Jul 31 00:53 .
drwxr-sr-x 9 faheem staff   4096 Jul 31 00:53 ..
drwxr-sr-x 2 faheem staff   4096 Jul 31 00:53 C
-rw-r--r-- 1 faheem staff 593125 Jul 31 00:53 constants.cdb
[more .cdb files]

./libc/C:
total 20
drwxr-sr-x 2 faheem staff  4096 Jul 31 00:53 .
drwxr-sr-x 3 faheem staff  4096 Jul 31 00:53 ..
-rwxr-xr-x 1 faheem staff 10544 Jul 31 00:53 populate.sh
    
por Faheem Mitha 31.07.2012 / 02:48

6 respostas

3

Este não é um trabalho para find , já que não há recursão envolvida.

for x in */C/populate.sh; do
  mkdir -- "${x%%/*}$suffix"
  mkdir -- "${x%%/*}$suffix/C"
  cp -p -- "$x" "./${x%%/*}$suffix/C"
done

Remova a opção -p para cp se não quiser preservar o tempo de modificação dos arquivos.

Para gerar um sufixo aleatório, o BSD / Linux mktemp é tão portátil quanto possível.

suffix=$(mktemp -u tmp_XXXXX)

Se você quiser algo vagamente aleatório e compatível com POSIX, isso fornecerá uma string que muda a cada segundo e varia de local para local; você não pode fazer melhor com apenas as ferramentas POSIX:

suffix=$({ hostname; pwd; date; } |
         cksum | uuencode -m /dev/stdin | awk 'NR==2 {print substr($0,3,5)}')

Se você colocar este código em um makefile, lembre-se de:

  • dobre todos os sinais $ ;
  • coloque todo o código em uma linha, usando ; para separar as instruções da shell (você pode usar barra invertida + nova linha + tab para colocar uma quebra de linha no makefile, mas essa sequência é removida para construir o comando shell);
  • inicie o snippet de shell com set -e , para que seja cancelado se houver algum erro.
por 01.08.2012 / 02:14
1

Você pode criar uma cópia de todos os diretórios de nível superior usando

$ find . -maxdepth 1 -type d -exec mkdir {}".tmpvalue" \;

Você pode então iterar e copiar o arquivo .sh para cada um desses diretórios.

    
por 31.07.2012 / 04:31
1

Tente algo assim:

#!/bin/sh
# Create a temporary partial clone of the current directory
tcopy='mktemp -d /tmp/tmp_XXXXX'
tbase='basename $tcopy'
find . -name populate.sh -print | cpio -pud "$tcopy"

# Randomize the clone
for d in "$tcopy"/*
do
    mv "$d" "$d.$tbase"
done

# Merge the clone back into the current tree
mv "$tcopy"/* .

Isso depende de uma implementação mv que saiba como mover diretórios inteiros pelos sistemas de arquivos. GNU mv pode, mas eu me lembro de trabalhar em algumas caixas Unix antigas, onde a linha final não funcionaria. Você poderia usar outro find | cpio pass nesse caso. mv é mais eficiente se funcionar.

    
por 31.07.2012 / 04:03
1

Eu não me preocuparia muito com -print0 desde que os nomes dos arquivos sejam bem formados. Abaixo está um exemplo que deve fazer o que você quer:

rnd=$(tr -cd a-z0-9 < /dev/urandom | head -c5)
find . -maxdepth 1 -type d | while read dir; do
   mkdir -p ${dir}_${rnd}/C
   cp populate.sh ${dir}_${rnd}/C
done

Explicação

  • tr -cd exclui o complemento do padrão especificado, alfanuméricos neste caso.
  • head -c5 pega os primeiros cinco caracteres e sai.
  • while executa o comando read para cada linha que find fornece.
  • read atribui o diretório de find a $dir .
por 31.07.2012 / 04:45
1

Se outras pessoas pesquisarem como copiar find resultados e criar diretórios intermediários, você poderá usar --parents com GNU cp , rsync -R , pax -rw ou cpio -pd .

find . -type f -exec cp --parents -t /tmp {} +
  --parents creates intermediate directories in GNU cp
  -t specifies a target directory in GNU cp
find . -type f -print0|xargs -0I, rsync -R , /tmp
  -R is --relative
find . -type f|pax -rw /tmp
  -rw (read and write) copies files
  pax is required by POSIX but not LSB and not included by some Linux distributions
find . -type f|cpio -pdu /tmp
  -p (pass-through) copies paths from stdin to a specified directory
  -d creates intermediate directories
  -u unconditionally overwrites existing files
    
por 16.06.2014 / 07:36
0
cd usr/local/src/ccl/ccl-1.8/x86-headers
printf 'd=%s ; mkdir -p ${d}'$$'/C
     cp ${d}/C/populate.sh ${d}'$$'/C\n' * | sh

Isso cria um diretório chamado ${dir}${current_shells_pid}/C para cada um que você mostrou na sua saída ls na pergunta. Em seguida, copia o arquivo que você deseja da origem para o diretório de destino.

    
por 16.06.2014 / 08:48