Copie arquivos de mesmo nome no mesmo diretório

4

Eu tenho um grande número de pastas com um arquivo chamado genome.txt que eu preciso para cp na mesma pasta. Eu estou tentando descobrir como posso fazer isso para que os arquivos se pareçam com genome1.txt , genome2.txt , etc. Estou procurando uma solução simples para isso.

    
por JS Brewer 22.03.2017 / 20:44

1 resposta

4

Script de shell e seu uso

Isto pode ser feito com um simples shell script que faz uso de find ...|while read var ; do ... done structure (muito comum em lidar com nomes de arquivos). O script bash abaixo opera no diretório atual (top-most) e leva um único argumento para o destino.

#!/bin/bash
find -name "genome.txt" -print0 | while IFS= read -r -d '' path
do
    base=$(basename --suffix=".txt"  "$path")
    new_path="${1%/}"/"$base"$counter".txt"
    echo "$path" "$new_path"
    counter=$(( $counter +1 ))
done

> > > OBSERVAÇÃO < < < : o script usa echo apenas para fins de teste. Quando estiver satisfeito com os caminhos resultantes, substitua echo por mv para mover todos os nomes de arquivos ou cp para copiar todos os nomes de arquivos.

Exemplo:

bash-4.3$ tree
.
├── destination
├── dir1
│   └── genome.txt
├── dir2
│   └── genome.txt
├── dir3
│   └── genome.txt
└── move_enumerated.sh

4 directories, 4 files
bash-4.3$ ./move_enumerated.sh  ./destination
./dir2/genome.txt ./destination/genome.txt
./dir3/genome.txt ./destination/genome1.txt
./dir1/genome.txt ./destination/genome2.txt

Melhorando o script para mais flexibilidade

Esse script pode ser melhorado para torná-lo mais genérico, onde o usuário pode especificar o nome do arquivo, o diretório superior a ser percorrido e o destino como argumentos da linha de comando:

#!/bin/bash
find "$2"  -name "$1" -print0 | while IFS= read -r -d '' path
do
    base=$(basename --suffix=".txt"  "$path")
    new_path="${3%/}"/"$base"$counter".txt"
    echo "$path" "$new_path"
    counter=$(( $counter +1 ))
done

Execução de teste:

bash-4.3$ ./move_enumerated.sh "genome.txt"  "./testdir" "./testdir/destination"
./testdir/dir2/genome.txt ./testdir/destination/genome.txt
./testdir/dir3/genome.txt ./testdir/destination/genome1.txt
./testdir/dir1/genome.txt ./testdir/destination/genome2.txt

Sintaxe e teoria de operação

Em todo o script, é utilizado o command | while read variable ; do ... done structure. Esta é uma abordagem muito comum, e é freqüentemente usada para evitar lidar com ls e nomes de arquivos difíceis que podem quebrar scripts.

No lado esquerdo do pipe, temos o comando find , que toma o diretório como argumento (e se isso não for fornecido, o GNU find , que é usado no Linux, assume . - o diretório de trabalho atual). As outras opções incluem -name , que é o nome de arquivo específico que estamos pesquisando, e -print0 , que é usado para gerar resultados como delimitados por caractere while IFS= read -r -d '' ; do . . . done não imprimível. É freqüentemente usado para evitar a divisão na nova linha ou em outros caracteres, porque esses caracteres podem aparecer no próprio nome do arquivo e, como resultado, quebrar o script.

No lado direito do tubo, temos while structure. O loop read com stdin shell embutido é freqüentemente usado para% realIFS= input, que neste caso vem do pipe. -r -d '' e basename são necessários para garantir que recebamos nomes de arquivos com segurança e reconhecemos que cada item é delimitado com --suffix=".txt" .

O resto do script é bastante fácil. Extraímos o nome da base do arquivo usando o comando genome . Como neste caso estamos lidando especificamente com a extensão conhecida e esperamos ter um único ponto no nome do arquivo, podemos usar "${3%/}" para remover essa parte, deixando / part. Em seguida, criamos um novo caminho para o arquivo, unindo o destino, o nome da base e a variável do contador. Observe que usamos a expansão de parâmetro com ./destination argumento (pasta de destino) em nosso script aprimorado. Isso é feito para garantir que, independentemente de o usuário ter ou não adicionado ./destination/ caracteres na linha de comando ( / ou counter ), extraímos apenas o nome do diretório simples e o associamos por meio de genome.txt com basename. Observe também que a variável %code% não é configurada inicialmente, portanto, o primeiro nome de arquivo que recebermos será %code% Depois, a variável do contador será incrementada e, portanto, criada e mostrada quando lidamos com outros nomes de arquivos. p>

Para obter mais informações, leia Nomes de arquivo e nomes de caminho no Shell: como fazer corretamente .

    
por Sergiy Kolodyazhnyy 22.03.2017 / 21:44