Busque una cadena en un archivo y cambie el nombre de varios archivos según los resultados

Busque una cadena en un archivo y cambie el nombre de varios archivos según los resultados

Estoy intentando buscar recursivamente en una lista de archivos y, si el archivo contiene una cadena, cambiarle el nombre al resultado de grep de dicha cadena.

Los archivos de muestra contienen el siguiente contenido:

file1   
foo bar1

file2
foo bar2

file3
foo bar3

file4
foo bar4

file5
foo bar5

grep + awk devuelven los resultados que necesito:

$ grep -r "^foo" . | awk '{print $2}'
bar1
bar2
bar3
bar4
bar5

Estoy atascado al pasar estos resultados a un comando mv.

$ grep -r "^foo" . | awk '{print $2}' | xargs -I{} mv {} .
mv: cannot stat 'bar1': No such file or directory
mv: cannot stat 'bar2': No such file or directory
mv: cannot stat 'bar3': No such file or directory
mv: cannot stat 'bar4': No such file or directory
mv: cannot stat 'bar5': No such file or directory

Gracias de antemano. Gnu/BSD Grep ambos tienen los mismos resultados.

Respuesta1

Yo usaría un bucle for de shell:

for match in "$(grep -ro '^foo.*')";do
    echo mv "${match%:*}" "${match#*:}"
done

Esto iterará todas las coincidencias file:matching-substringy utilizará los operadores de cadena %y #para eliminar todo hasta, resp. todo lo posterior, incluido :.

Tenga en cuenta que si realmente desea hacer coincidir toda la línea en lugar de solo la subcadena que coincide con el patrón, use

for match in $(grep -r '^foo');do

Asegúrese de poner comillas dobles, ya que las coincidencias y/o los nombres de archivos pueden contener espacios.

Si desea hacer coincidir un patrón pero cambiar el nombre del archivo a la segunda palabra en la línea coincidente:

for match in "$(grep -ro '^foo.*')";do
    fname=$("echo ${match#*:}|awk '{print $2}'")
    echo mv "${match%:*}" "$fname"
done

Respuesta2

Puedes hacer lo que intentas lograr usando Perl:

#!/usr/bin/env perl
use strict;

my $dir = "/path/to/directory";
chdir $dir or die "Cannot open $dir!";

my @files = grep { -f } glob("*");

foreach my $file(@files) {
  open F1, "<", $file or die "Cannot open file $file! $!\n";
  while ( <F1> ){
    chomp;
    my @strings = split(' ');
    if($strings[1] =~ /bar/){
      system("/bin/mv $file $strings[1]");
    }
  }
  close(F1);
}

Respuesta3

find . -type f -exec egrep -il '^foo' {} \; | sort | while IFS='' read -r line; do mv -n "$line" "$(dirname "$line")"'/'"$(egrep -i '^foo' "$line" | awk '{ print $2 }')"; done

información relacionada