我正在尝试递归搜索文件列表,如果该文件包含字符串,则将该文件重命名为该字符串的 grep 结果。
示例文件包含以下内容:
file1
foo bar1
file2
foo bar2
file3
foo bar3
file4
foo bar4
file5
foo bar5
grep + awk 返回我需要的结果:
$ grep -r "^foo" . | awk '{print $2}'
bar1
bar2
bar3
bar4
bar5
我坚持将这些结果传递给 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
提前致谢。 Gnu/BSD Grep 都有相同的结果。
答案1
我会使用 shell for 循环:
for match in "$(grep -ro '^foo.*')";do
echo mv "${match%:*}" "${match#*:}"
done
这将迭代所有匹配file:matching-substring
,并使用%
和#
字符串运算符删除所有内容。之后的所有内容,包括:
.
请注意,如果您确实想匹配整行而不是仅匹配模式的子字符串,请使用
for match in $(grep -r '^foo');do
确保使用双引号,因为匹配项和/或文件名可能包含空格。
如果您想按一种模式进行匹配,但将文件重命名为匹配行中的第二个单词:
for match in "$(grep -ro '^foo.*')";do
fname=$("echo ${match#*:}|awk '{print $2}'")
echo mv "${match%:*}" "$fname"
done
答案2
您可以使用 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);
}
答案3
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