2015-09-02 2 views
3

У меня есть набор файлов .csv, которые я пытаюсь очистить. Каждый из них имеет такие данные:Bash работает в командной строке, но не в perl-скрипте

x0,"","","" 
x1,123,456,789 
x2,123,456,789 
x3,123,456,789 
-,"","","" 
x4,123,456,789 
[space],____,____,____ 
x5,123,456,789 
x6,===,====,====== 
x7,---,--------=--,------- 

Я хочу, чтобы удалить все строки, которые не хп, ###, ###, ###, поэтому в данном примере, было бы строки 1, 5, 7 , 9 и 10. В командной строке cygwin я печатаю следующие команды 1 по 1:

sed -i '/"",""/d' *.csv 
    sed -i '/___/d' *.csv 
    sed -i '/---/d' *.csv 
    sed -i '/===/d' *.csv 

и все эти работы. Однако, когда я пытаюсь поставить их вместе в Perl-скрипт (остальная часть моего кода в Perl, они не:

system("sed -i '/"",""/d' *.csv"); 
    system("sed -i '/___/d' *.csv"); 
    system("sed -i '/---/d' *.csv"); 
    system("sed -i '/===/d' *.csv"); 

и я получаю результат:

строку, найденную где оператор ожидается на test1.pl линии 1, возле "" СЭД -i «/ "", ""

(Missing оператор раньше ""?)

Строка найден где оператор ожидается на test1.pl линии 1, рядом "", ""/d '* .csv ""

(Отсутствует оператор перед "/ г» * .csv"?) Ошибки

синтаксиса в test1.pl строке 1, рядом с "" СЭД -i"/"", ""

I заметьте все работы за исключением того, что первая команда - есть ли что-то особенное о "" в sed? Любая помощь будет оценена! Более простое решение приветствуется!

+2

Вы не можете использовать двойные кавычки внутри двойных кавычек таким образом (первая команда). –

+7

Почему вы вызываете sed из perl? Было бы гораздо лучше реализовать эти замены, используя собственные функции perl. –

ответ

2

Если остальная часть вашего скрипта находится в Perl, я настоятельно рекомендую заменить ваши вызовы на sed с помощью собственной реализации.

Например, замены, сделанные вами с помощью СЭД можно было бы заменить чем-то вроде этого:

use strict; 
use warnings; 

for my $file (glob '*.csv') { 
    open my $in, '<', $file;   
    my @lines; 
    while (<$in>) { 
     next if /"",""/; 
     next if /___/; 
     next if /---/; 
     next if /===/; 
     push @lines, $_; 
    } 
    close $in; 

    # this will overwrite your files! 
    # change $file to something else to test 
    open my $out, '>', $file; 
    print $out $_ for @lines; 
} 

Этот цикл по каждому файлу, заканчивающийся в .csv, чтение каждой строки. Он пропускает любые строки, которые соответствуют одному из шаблонов (вы можете сделать это, используя одно регулярное выражение с | между каждым шаблоном, если хотите, но я оставил его так же, как ваши вызовы sed). Он перемещает оставшиеся строки в массив. Затем он снова открывает входной файл для записи и печати массива.

Предоставлено, оно немного длиннее с точки зрения количества строк, но это экономит вам использование system для вызова внешних команд, когда Perl более чем способен. Это также означает, что каждый файл открывается только один раз, а не один раз для замены, как в вашем исходном коде.

+1

Возможно, вы можете использовать регулярное выражение, такое как 'm/^ x \ d, \ d +, \ d +, \ d + $ /', чтобы искать строки, которые точно соответствуют символам 'xn, ###, ###, ## # ', которые требуются, с различными настройками, чтобы сделать, если требуются правила, например, одна или несколько цифр после« x »(а не ровно одна, как показано), или ровно три цифры в других группах (а не одна или больше, как показано). –

+0

@ Jonathan Я намеренно оставил шаблоны так, чтобы они поняли, как они вписываются в скрипт, но я согласен, что почти наверняка будет возможно улучшить их, возможно, путем «белых списков», а не пропускать те, которые не совпадают как ты говоришь. Конечно, это зависит от разнообразия входных данных и требований OP. –

+0

@Tom Fenech: Спасибо за вашу помощь. Это, безусловно, лучшее решение - я довольно новичок в Perl (и программировании в целом), поэтому я стараюсь избегать использования его порой ... есть ли способ легко избавиться от определенного персонажа в то время цикл? В последней строке этих файлов перед первой строкой предшествует «-», и я пытаюсь избавиться от нее без помощи sed. Эта строка является «-TOTAL BE». Прямо сейчас я вставил следующее, но он, похоже, не работает: 'my $ str2 =" -TOTAL BE "; while (<$in>) { $ str2 = ~ s/- // g; next if/"", "";; и т. Д. И т. Д. – JDY

2

Проблема заключается в том, что двойные кавычки внутри аргумента sed заканчивают строку Perl. Вам нужно бежать им

system("sed -i '/`"`",`"`"/d' *.csv"); 

Или вы можете использовать q(...).

system(q(sed -i '/"",""/d' *.csv)); 

BTW, вы можете дать несколько команд sed, так что вам не нужно запускать его несколько раз.

system(q(sed -i -e '/"",""/d' -e '/___/d' -e '/---/d' -e '/===/d' *.csv")); 

или вы можете использовать регулярное выражение с чередованием для соответствия всем шаблонам одновременно.

system(q(sed -i -e '/"",""\\|___\\|---/\\|===/d' *.csv")); 
+2

'Лучше использовать 'q (...)', так как не требуется расширения? Но лучше не использовать 'sed' вообще; Perl был разработан как «sed'-killer. Вот почему есть (все еще) 's2p' для преобразования' sed' в Perl. –

+0

@ JonathanLeffler Я просто понял то же самое. – Barmar

+0

Если это всего лишь один маленький шаг в общем скрипте perl, переписывание всего объекта в perl может быть излишним. – Barmar

2

используйте escape-символ \, чтобы интерпретатор понял, что (", *,.) Внутри команды sed не то же самое, что и Perl (", *,.), А следует рассматривать их как строковый шаблон для команды sed ,

system("sed -i '/\"\",\"\"/d' \*\.csv"); 
    system("sed -i '/___/d' \*\.csv"); 
    system("sed -i '/---/d' \*\.csv"); 
    system("sed -i '/===/d' \*\.csv"); 
Смежные вопросы