Suchen Sie nach einer Zeichenfolge in einer Datei und benennen Sie mehrere Dateien in die Ergebnisse um

Suchen Sie nach einer Zeichenfolge in einer Datei und benennen Sie mehrere Dateien in die Ergebnisse um

Ich versuche, eine Liste von Dateien rekursiv zu durchsuchen und, wenn die Datei eine Zeichenfolge enthält, die Datei in die Grep-Ergebnisse dieser Zeichenfolge umzubenennen.

Die Beispieldateien enthalten folgenden Inhalt:

file1   
foo bar1

file2
foo bar2

file3
foo bar3

file4
foo bar4

file5
foo bar5

grep + awk geben die Ergebnisse zurück, die ich brauche:

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

Ich kann diese Ergebnisse nicht an einen MV-Befehl übergeben.

$ 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

Vielen Dank im Voraus. Gnu/BSD Grep haben beide die gleichen Ergebnisse.

Antwort1

Ich würde eine Shell-For-Schleife verwenden:

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

Dadurch werden alle Übereinstimmungen durchlaufen file:matching-substringund mithilfe der %Zeichenfolgenoperatoren und #alles bis bzw. alles danach und einschließlich gelöscht :.

Beachten Sie, dass wenn Sie wirklich die ganze Zeile abgleichen wollen und nicht nur die Teilzeichenfolge, die dem Muster entspricht, verwenden Sie

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

Stellen Sie sicher, dass Sie doppelte Anführungszeichen verwenden, da Übereinstimmungen und/oder Dateinamen Leerzeichen enthalten können.

Wenn Sie eine Übereinstimmung nach einem Muster erzielen möchten, die Datei aber in das zweite Wort in der übereinstimmenden Zeile umbenennen möchten:

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

Antwort2

Sie können das gewünschte Ergebnis mit Perl erzielen:

#!/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);
}

Antwort3

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

verwandte Informationen