简体   繁体   English

在单个命令行中执行grep和sed

[英]Doing grep and sed in a single command line

I have written a perl script with two arrays. 我写了一个带有两个数组的perl脚本。 My first array contains a list of names and my second array contains a list of names that I would like to replace the first names with. 我的第一个数组包含一个名称列表,而我的第二个数组包含一个我想用其替换名字的列表。

This is a quick and dirty script I'm writing just to get something done so I do not have to do the manual work. 这是我写的一个快速而肮脏的脚本,只是为了完成某件事,所以我不必做手工工作。 It's not something I am focusing on looking "clean" or super efficient. 我并不是要着眼于“干净”或超高效。 For that reason, I'm making use of system a lot. 因此,我经常使用该system

A sample directory that I am using would look like this: 我正在使用的示例目录如下所示:

/myDir/Names/John/ containing files John.log, John.txt, RandomFile.html / myDir / Names / John /包含文件John.log,John.txt,RandomFile.html

John.log John.log

John is an engineer.
Jack and John are friends.

John.txt John.txt

John is 48 years old. 

where John is an element in my first array. 约翰是我第一个数组中的元素。 I want to be able to replace John with, for example, Mary from my second array IN FILES THAT CONTAIN JOHN IN THE FILE NAME. 我希望能够用第二个数组中的Mary替换John,例如在文件名中包含JOHN的文件中。 I want the element of that array to change to the corresponding element number in the next array. 我希望该数组的元素更改为下一个数组中的相应元素编号。 Here is what I've come up with: 这是我想出的:

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

my @firstnames = (John, Jack, Jill);
my @secondnames = (Mary, Nick, Joseph);

foreach my $old (@firstnames){
    foreach my $new (@secondnames){
         system("grep -rl $old /myDir/Names/$old/ | xargs sed -i 's/$old/$new/g' $old.* ");
        system("rename '$old' '$new' /myDir/Names/$old.*");
     }
}

Grep seems to work fine, Rename and Sed does not because of the '.*'. Grep似乎可以正常工作,重命名和Sed并不是因为'。*'。 The issue is where I have $old.* . 问题是我有$old.* It appropriately substitutes $old with the correct element in the array but it looks for files called John.* , Jack.* , Jill.* instead of reading .* as any file extension. 它会适当地用数组中的正确元素替换$ old,但是它将查找名为John.*Jack.*Jill.*而不是将.*读取为任何文件扩展名。 Clearly, I am not understanding how sed works entirely. 显然,我不了解sed的工作原理。 I would like some help as to how I can do the sed command for all files containing $old wit ANY file extension, because there might be multiple files in the directories with same names and different extensions. 我想对所有包含$old wit ANY文件扩展名的文件执行sed命令的帮助,因为目录中可能存在多个具有相同名称和不同扩展名的文件。 The reason I specify the first name with any extension is because the file might contain something like RandomFile.html that I listed above and I only want files that contain $old before extension. 我以任何扩展名指定名字的原因是,该文件可能包含上面列出的类似RandomFile.html ,并且我只希望扩展名前包含$old文件。

This is the output that I want, where the files names along with the words found in the text will be replaced with the corresponding element from the second array: 这是我想要的输出,其中文件名以及在文本中找到的单词将被第二个数组中的相应元素替换:

Mary.log Mary.log

Mary is an engineer.
Jack and Mary are friends.

Mary.txt Mary.txt

Mary is 48 years old. 

Note: The words that are in the file, match the name of the file they are in, which match the name of the directory they are in. That is the pattern of these Directories and their files. 注意:文件中的单词与它们所在文件的名称匹配,与它们所在目录的名称匹配。这就是这些目录及其文件的模式。

Please let me know if anything is unclear and I will edit my post. 如果有任何不清楚的地方,请告诉我,我将编辑我的帖子。

So the issue here is that you're piping a list of filenames into xargs already which get passed to sed. 因此,这里的问题是,您正在将文件名列表传递到xargs中,并将其传递给sed。 You cannot have sed take the intersection of all filenames that have the desired words in them AND the contents of those files as well. sed不能使所有包含所需单词的文件名和这些文件的内容相交。 You will need to first find all the files with the desired contents, filter out the filenames you do not care about, THEN feed that list into xargs sed. 您首先需要找到所有具有所需内容的文件,过滤掉您不关心的文件名,然后将该列表输入xargs sed。 Try: 尝试:

system("grep -rl $old /myDir/Names/$old/ | grep $old | xargs sed -i 's/$old/$new/g'");

I was having issues with grep that I was not able to entirely trace down so I used find instead which seems to do the trick. 我在grep方面遇到问题,无法完全追踪,因此我改用find来解决问题。 Here is what I'm using now that works just fine: 这是我现在正在使用的,可以正常工作:

find ./$old -name "$old.*" -exec gsed -i -e "s/$old/$new/Ig" {} +

Another important issue to note that is not particularly related to the problem in the question is that I am incorrectly using the foreach loop. 需要注意的另一个与该问题没有特别关系的重要问题是我错误地使用了foreach循环。 In order to match each element in the arrays, you have to iterate through the size of the array. 为了匹配数组中的每个元素,您必须遍历数组的大小。

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

my $i = scalar @firstnames;
for ($i=0; $i < @firstnames; $i++){
.......
 }

.Hi sfr. 嗨,sfr。 This will do the job although there is no error checking. 尽管没有错误检查,但这可以完成工作。

#!perl

use strict;
use diagnostics;
use File::Glob "bsd_glob";
use List::MoreUtils "mesh";
use Data::Dumper "Dumper";
our $basedir = "/myDir/Names";
our @oldnames = qw/John Jack Jill/;
our @newnames = qw/Mary Nick Joseph/;
our %namemap = mesh @oldnames, @newnames;
printf "oldnames:%s\nnewnames: %s\nnamemap:%s\n\n", map Dumper($_), \@oldnames, \@newnames, \%namemap;

foreach my $searchname (keys %namemap) {
    print "searchname: $searchname, glob: $basedir/$searchname/*$searchname*";
    my @files = bsd_glob "$basedir/$searchname/*$searchname*";
    printf "files %s\n", Dumper \@files;

    next unless @files;
    local $/;
    foreach my $file (@files) {
        print "on file $file\n";
        open my $F, "+<", $file or die "open $file: $!";
        my $text = readline $F;
        print "changing all $searchname to $namemap{$searchname}\n";
        if (my $c = $text =~ s/\b$searchname\b/$namemap{$searchname}/g) {
            print "replaced $c occurrences\n";
            seek $F, 0, 0 or die "seek $file: $!";
            print $F $text or die "print $file: $!";
            print "wrote changes to file\n";
            close $F or die "closing $file: $!";
        }
        else { print "file did not contain any $searchname\n"; }
        (my $newfile = $file) =~ s/\b$searchname\b/$namemap{$searchname}/g;
        print "renaming $file to $newfile\n";
        rename $file, $newfile or die "rename: $!";
    }
}

LA LA

EDIT: code updated 编辑:代码已更新

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM