Copiando certos arquivos correspondendo parcialmente seus nomes a uma lista dentro de um arquivo de texto

3

Eu tenho um diretório com arquivos com nomes de string que começam com 5 números (ie 12345_a_b, 23456_s_a) e eu tenho um arquivo de texto dentro do mesmo diretório que tem uma lista de nomes de arquivos nomeados da mesma maneira, porém somente os números correspondem e nada após o sublinhado (por exemplo, 12345_q_p, 23456_p_l). Eu quero copiar arquivos no diretório atual para um novo, mas apenas aqueles onde os primeiros 5 números no nome do arquivo correspondem aos primeiros 5 números de cada nome de arquivo no arquivo de texto, ignorando tudo o que vem depois. Parece que eu posso usar xargs, mas não sei como combinar os nomes parcialmente. Alguém pode ajudar?

    
por user5654627 26.01.2017 / 11:14

3 respostas

4

Itere nas linhas com _ como IFS , obtenha a primeira parte desejada contendo dígitos e copie os arquivos começando com esses dígitos:

shopt -s nullglob
while IFS=_ read -r i _; do [[ $i =~ ^[0-9]{5}$ ]] && echo cp -it dest/ "${i}"*; done <file.txt

Expandido:

#!/bin/bash
shopt -s nullglob  ##Expands to null string if no match while doing glob expansion,
                   ##rather than the literal
while IFS=_ read -r i _; do  ##Iterate over the lines of file.txt, 
                              ##with '_' as the 'IFS' i.e. word splitting 
                              ##happens on each '_' only, variable 'i' 
                              ##will contain the digits at start; '_' is a
                              ##throwaway variable containing the rest
    [[ $i =~ ^[0-9]{5}$ ]] \ ##Check if the variable contains only 5 digits
      && echo cp -it /destination/ "${i}"*  ##if so, copy the relevant files starting with those digits
done <file.txt

Substitua file.txt pelo arquivo de origem real e /destination/ pelo diretório de destino real. Aqui, echo está incluído para fazer o teste de secagem; se satisfeito com os comandos a serem executados, é só se livrar de echo :

shopt -s nullglob
while IFS=_ read -r i _; do [[ $i =~ ^[0-9]{5}$ ]] && cp -it dest/ "${i}"*; done <file.txt
    
por heemayl 26.01.2017 / 11:27
2

Os seguintes comandos devem fazer o truque, você pode trocar as primeiras atribuições de variáveis com seus valores literais dentro do loop while, se preferir.

#!/bin/bash
source_dir=/directory/containing/files
target_dir=/new/directory
list=/full/path/to/number_list
reg='^[0-9]{5}$' 

while IFS= read -r line; do
   line=${line:0:5}
   [[ "$line" =~ $reg ]] && cp -t "$target_dir" "$source_dir"/"$line"* 2>/dev/null
done < "$list"
  • O comando read lerá seu arquivo linha por linha, definindo o conteúdo de cada linha na variável 'linha'.
  • O comando cp usa -t para definir o destino para copiar arquivos, e o padrão de glob "$source_dir"/"$line"* encontrará todos os arquivos no diretório de origem que iniciam com o valor numérico na variável de linha.
  • O loop while significa que os comandos read e cp são executados para cada linha do arquivo de lista. IFS= significa que se houver espaços em seu arquivo de lista, eles serão incluídos na string de pesquisa, não é diretamente necessário neste exemplo, mas é útil geralmente quando você deseja ler um arquivo linha por linha.
por Arronical 26.01.2017 / 11:25
1

Execute um loop em seus arquivos. Dentro do loop, descubra se os nomes de arquivos combinam com os nomes de arquivos em seu arquivo de texto usando grep .

Usando -q, use && cp se encontrar algo.

#!/bin/bash
while IFS= read -r file; do
  grep -Eq "^${f:0:5}" your_text_file && cp ${file} /path/to/destination/
done <( (find . -type f -regex "^[0-9]{5}.*")

Isso terá alguma sobrecarga quando você tiver um grande número de arquivos. Mas também pode ser usado para tarefas mais complexas ...

    
por RoVo 26.01.2017 / 11:26