簡體   English   中英

在帶有CSV的文本文件上使用sed

[英]Using sed on text files with a csv

我一直在嘗試使用csv對兩個文本文件進行批量查找和替換。 我已經看到了SO提出的問題,但似乎沒有人回答我的問題。

我為要修改的兩個文本文件創建了兩個變量。 CSV具有兩列和幾百行。 第一列包含文本文件中已經存在的字符串(沒有空格),需要用第二列同一行中的相應字符串替換。

作為測試,我嘗試了腳本

#!/bin/bash

test1='long_file_name.txt'
find='string1'
replace='string2'

sed -e "s/$find/$replace/g" $test1 > $test1.tmp && mv $test1.tmp $test1

這是成功的,除了我需要使用每行中csv給定的值對csv中的每一行執行一次。 我的直覺是我的while循環被錯誤地使用,但是我找不到錯誤。 當我執行下面的腳本時,我得到命令行提示符,這使我認為事情已經發生了。 當我檢查文本文件時,沒有任何改變。

這兩個文本文件,此腳本和csv都在同一文件夾中(當我執行此操作時,這也是我的工作目錄)。

#!/bin/bash

textfile1='long_file_name1.txt'
textfile2='long_file_name2.txt'

while IFS=, read f1 f2
do
    sed -e "s/$f1/$f2/g" $textfile1 > $textfile1.tmp && \
         mv $textfile1.tmp $textfile1
    sed -e "s/$f1/$f2/g" $textfile2 > $textfile2.tmp && \
         mv $textfile2.tmp $textfile2
done <'findreplace.csv'

在我看來,這段代碼應該按照我想要的去做(但不是); 也許我誤解了一些基本知識(我是bash腳本的新手)?

csv看起來像這樣,但是有數百行。 在下一列中,所有a_i應替換為其對應的b_i。

a_1 b_1
a_2 b_2
a_3 b_3

注意事項:所有字符串實際上都包含下划線,以防萬一這會影響某些內容。 我試過將變量名用大括號$ {var}括起來,但是仍然不起作用。

我很欣賞這些解決方案,但也很想知道為什么上述方法不起作用。 (此外,我會投票給所有人,但我沒有這樣做的聲譽。但是,請注意,我很感激,並從您的回答中學到很多東西!

如果您要處理大量數據,並且您的模式可以包含特殊字符,我會考慮使用Perl。 尤其是在findreplace.csv要有很多對的findreplace.csv 您可以使用以下腳本作為篩選器或對很多文件進行就地修改。 副作用是,它每次調用僅加載一次替換並創建Aho-Corrasic自動機,這將使該解決方案非常有效(解決方案中的O(M+N)而不是O(M*N) )。

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

my $in_place = ( @ARGV and $ARGV[0] =~ /^-i(.*)/ )
    ? do {
    shift;
    my $backup_extension = $1;
    my $backup_name      = $backup_extension =~ /\*/
        ? sub { ( my $fn = $backup_extension ) =~ s/\*/$_[0]/; $fn }
        : sub { shift . $backup_extension };
    my $oldargv = '-';
    sub {
        if ( $ARGV ne $oldargv ) {
            rename( $ARGV, $backup_name->($ARGV) );
            open( ARGVOUT, '>', $ARGV );
            select(ARGVOUT);
            $oldargv = $ARGV;
        }
    };
    }
    : sub { };

die "$0: File with replacements required." unless @ARGV;
my ( $re, %replace );
do {
    my $filename = shift;
    open my $fh, '<', $filename;
    %replace = map { chomp; split ',', $_, 2 } <$fh>;
    close $fh;
    $re = join '|', map quotemeta, keys %replace;
    $re = qr/($re)/;
};

while (<>) {
    $in_place->();
    s/$re/$replace{$1}/g;
}
continue {print}

用法:

./replace.pl replace.csv <file.in >file.out

以及

./replace.pl replace.csv file.in >file.out

或就地

./replace.pl -i replace.csv file1.csv file2.csv file3.csv

或帶備份

./replace.pl -i.orig replace.csv file1.csv file2.csv file3.csv

或帶備用絲毫占位符

./replace.pl -ithere.is.\*.original replace.csv file1.csv file2.csv file3.csv

您應該使用以下命令將CSV文件轉換為sed.script:

cat replace.csv | awk -F, '{print "s/" $1 "/" $2 "/g";}' > sed.script

然后,您將可以進行一次通行證更換:

sed -i -f sed.script longfilename.txt

這將是您想做的事的更快實現。

順便說一句,對不起,但是我不明白您的腳本有什么問題,該腳本應該可以工作,除非您的CSV文件有兩列以上。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM