Trim substrings de um nome de arquivo, cada um correspondendo a um padrão para um determinado tamanho

0

No exemplo a seguir, o padrão é separado por - e o tamanho é 3. Minha pergunta é: existe uma maneira mais eficiente de fazer isso?

$ echo $foo
./abcd-123-efghij-45678.pdf
$ echo "$foo" | sed -E 's:([^-\.\/]{3})([^-]*)::g'| sed "s/$/.${foo##*.}/"
./abc-123-efg-456.pdf
$ foo=${foo%.pdf}.djvu
$ echo $foo
./abcd-123-efghij-45678.djvu
$ echo "$foo" | sed -E 's:([^-\.\/]{3})([^-]*)::g'| sed "s/$/.${foo##*.}/"
./abc-123-efg-456.djvu

O que eu preciso no final deste comando é substituir ... por dentro de for f in $(find . -name pattern); do mv $f $(...);done

    
por Erwann 09.08.2016 / 06:15

3 respostas

0

Você pode encurtar isso para

echo ./abcd-123-efghij-45678.pdf | sed -E 's:([^-\.\/]{3})([^-]*)::g; s/$/.djvu/'

mas por outro lado, é praticamente o melhor que você pode fazer com sed .

    
por 09.08.2016 / 08:46
0

Acho que isso ajudaria você, por exemplo, você quer pesquisar todos os *.txt files

for f in $(find . -type f -name "*.txt"); 
 do 
    echo mv "$f" $(echo "$f" | sed -E 's:([^-\.\/]{3})([^-]*)::g;s/$/.'"${f##*.}"'/')
done

Se você estiver satisfeito com o resultado, remova echo e execute o código novamente.

    
por 09.08.2016 / 08:58
0

Aqui está um script simples de perl . Duvido muito se for mais "eficiente" em termos de uso da CPU ou consumo de memória do que sed , mas é muito improvável que você note qualquer diferença no tempo de execução e seja mais fácil de ler, modificar e usar:

#! /usr/bin/perl

use strict;
use warnings;

# default to substring lengths of 3
my $maxlen=3;
if ($ARGV[0] =~ m/^\d+$/) {  # if first arg contains only digits
  $maxlen = shift;
};

while(<>) {
  chomp;
  s/#.*|^\s*|\s*$//g;  # strip '#' comments, leading & trailng spaces
  next if (m/^$/);     # skip blank lines

  my ($path,$ext) = '';
  my $filename = $_;

  # extract path (if any)
  if (m/^(.*\/)(.*)/o) {
    ($path,$filename) = ($1,$2)
  };

  # extract filename extension (if any)
  if ($filename =~ m/(^.*)(\..*)$/) {
    ($filename,$ext) = ($1,$2);
  };

  # split into fields on '-', reduce each field to $maxlen.
  my @fields=split /-/,$filename;
  @fields = map { substr($_,0,$maxlen-1) } @fields;

  print "$path" . join('-',@fields) . $ext . "\n";
}

Salve o script com um nome de arquivo descritivo e torne-o executável com chmod +x scriptname . Acabei de usar seu nome U & L.

Entrada:

==> erwann1.txt <==
abcd-123-efghij-45678.pdf
./abcd-123-efghij-45678.djvu

==> erwann2.txt <==
gtr-tomwaits-callfromistanbul-chord-ehaugen.mp4 
gtr-tomwaits-callfromistanbul-mribot.mp4 

Saída:

$ ./erwann.pl 3 erwann1.txt 
abc-123-efg-456.pdf
./abc-123-efg-456.djvu

$ ./erwann.pl 6 erwann2.txt 
gtr-tomwai-callfr-chord-ehauge.mp4 
gtr-tomwai-callfr-mribot.mp4 

Você pode executá-lo como:

ls -1 *.mp4 | ./erwann.pl 6
find . -type f -name '*.pdf' | ./erwann.pl 

O script lidará com nomes de arquivos com qualquer caractere, exceto novas linhas neles. Se houver alguma chance de que nomes de arquivos tenham novas linhas neles, o script é facilmente modificado para suportar registros de entrada terminados em NUL (talvez use Getopt::Std ou Getopt::Long para manipular opções de linha de comando)

    
por 09.08.2016 / 12:29