Copia vários arquivos do nome de arquivo X para o nome de arquivo Y?

7

O que eu quero fazer é copiar arquivos dentro de um intervalo lexicográfico.

Exemplo de arquivos:

-rw-r--r--   1 root root   15276 Oct  5  2004 a2ps.cfg
-rw-r--r--   1 root root    2562 Oct  5  2004 a2ps-site.cfg
-rw-r--r--   4 root root    4096 Feb  2  2007 acpi.txt
-rw-r--r--   1 root root      48 Feb  8  2008 adjtime.jpg
-rw-r--r--   4 root root    4096 Feb  2  2007 alchemist.jpg

Exemplo de uso:

  • Copie os 3 arquivos de asps.cfg para acpi.txt
  • Copie os 3 arquivos de a2ps-site.cfg para adjtime.jpg
  • Copie os 4 arquivos de a2ps-site.cfg para alchemist.jpg

Então existe alguma maneira de copiar um intervalo de arquivos (do nome de arquivo X para o nome do arquivo Y) em um diretório?

Como: cp filenameX ... filenameY destination/

    
por Tiax 15.04.2011 / 17:30

4 respostas

4

Uma abordagem genérica é definir uma função de shell que imprima um intervalo de nomes de arquivos. Uma versão simples dessa função listará todos os arquivos entre dois nomes de arquivos, inclusive no diretório atual:

range()
{
    ls | sed -n "/^$1\$/,/^$2\$/p"
}

Isso usa um intervalo sed dizendo para imprimir qualquer coisa entre as duas strings dadas ( $1 e $2 ).

Você pode usar essa função no comando cp(1) :

cp $(range asps.cfg acpi.txt) /destination/path

Isso falhará se você tiver nomes de arquivos com espaços neles. Para isso, você precisa ficar um pouco mais complicado:

range asps.cfg acpi.txt | xargs -d '\n' -I {} cp {} /destination/path

Isso falhará se seus nomes de arquivo tiverem novas linhas (\ n) neles. Isso é muito improvável, então consertar isso é deixado como um exercício para o leitor.

Você pode juntar isso em outra função de shell:

cprange()
{
    [ $# -eq 3 ] || { echo "usage: cprange start end dir" >&2; return 1;}
    range "$1" "$2" | xargs -d '\n' -I {} cp {} "$3"
}

e use-o como:

cprange filenameX filenameY destination

Lembre-se, o intervalo funciona apenas para nomes de arquivos no diretório atual. Você pode expandir isso de várias maneiras (parâmetro de diretório adicional para range , extrair um caminho de argumentos para range usando dirname , etc), mas deixaremos isso para você com base em seus requisitos. Por favor, pergunte se você quiser mais detalhes aqui.

    
por 16.04.2011 / 05:14
3

O Zsh tem uma maneira fácil de selecionar um intervalo de arquivos fora do resultado de uma glob (uma glob é uma correspondência de caractere curinga). No lado positivo, o comando é muito curto para escrever. No site menos, você terá que descobrir os ordinais dos arquivos que deseja gravar. Por exemplo, o comando a seguir copia o 21º, 22º, ..., 40º arquivo com uma extensão .jpg no diretório atual, com os arquivos enumerados em ordem alfabética:

cp *.jpg([21,40]) destination/

O Zsh tem uma opção que pode ou não ser útil para você: em setopt numeric_glob_sort , foo9bar.jpg será classificado antes de foo10bar.jpg . Você também pode escolher uma ordem de classificação diferente nos qualificadores de glob, por exemplo cp *.jpg(om[21,40]) destination/ para escolher os arquivos mais recentes do 21º ao 40º (use% maiO para classificar na ordem oposta). Consulte qualificadores da glob no manual para obter mais informações.

Em qualquer shell, você pode escrever um loop que itera sobre os arquivos, inicia a cópia no primeiro arquivo que deseja gravar e pára após o último arquivo. Atenção, não testado.

in_range=
for x in *.jpg; do
  if [ "$x" = "first-file.jpg" ]; then in_range=1; fi
  if [ -n "$in_range" ]; then cp "$x" destination/; fi
  if [ "$x" = "last-file.jpg" ]; then break; fi
done
    
por 16.04.2011 / 15:17
0

O mais simples neste exemplo é usar M * para completar seu padrão e remover os que você não deseja copiar.

% cp *[hit Escape and press *]
->
% cp file1 file2 file3 file4 ... 

e, em seguida, basta remover manualmente os arquivos que você não deseja copiar. De qualquer forma, este é um recurso de shell, não cp 's.

Você pode refinar o padrão como desejar. Se você tivesse muitos outros arquivos no diretório e só quisesse copiar aqueles que começavam com a , você acabaria de iniciar o padrão com essa letra. Você pode querer pesquisar a documentação do shell sobre a globalização de nomes de arquivos. Por exemplo, link .

    
por 15.04.2011 / 17:35
0

Parece que os nomes dos arquivos são classificados e você parece distribuir em quantidades iguais.

Obtenha todos os nomes de arquivos em um único arquivo

ls > all_files

Divida o arquivo em lotes

split -l 4 all_files all_files-

Agora você tem 4 nomes de arquivos em cada arquivo, all_files-*

Escolha um, diga all_files-aa e faça sua cópia:

xargs -I{} cp {} folder_for_batch_1 < all_files-aa

    
por 16.04.2011 / 04:39

Tags