Линия Perl работает в 30 раз быстрее с одинарными кавычками, чем с двойными - PullRequest
6 голосов
/ 05 августа 2011

У нас есть задача изменить некоторые строки в двоичных файлах на строчные (от смешанного / верхнего / любого другого). Соответствующие строки являются ссылками на другие файлы (это связано с обновлением, когда мы также переходим с Windows на Linux в качестве серверной среды, поэтому случай вдруг имеет значение). Мы написали скрипт, который использует цикл perl для этого. У нас есть каталог, содержащий около 300 файлов (общий размер каталога составляет около 150 МБ), поэтому это некоторые данные, но не огромные.

Следующий perl-код занимает около 6 минут, чтобы выполнить работу:

for file_ref in `ls -1F $forms6_convert_dir/ | grep -v "/" | sed 's/\(.*\)\..*/\1/'` 
do
    (( updated++ ))
    write_line "Converting case of string: $file_ref "
    perl -i -pe "s{(?i)$file_ref}{$file_ref}g" $forms6_convert_dir/* 
done

, в то время как следующий код perl занимает более 3 часов!

for file_ref in `ls -1F $forms6_convert_dir/ | grep -v "/" | sed 's/\(.*\)\..*/\1/'` 
do
    (( updated++ ))
    write_line "Converting case of string: $file_ref "
    perl -i -pe 's{(?i)$file_ref}{$file_ref}g' $forms6_convert_dir/* 
done

Кто-нибудь может объяснить, почему? Это то, что $ file_ref остается в виде строки $ file_ref вместо того, чтобы заменяться значением в версии одинарных кавычек? в каком случае, что это заменяет в этой версии? Мы хотим заменить все вхождения любого имени файла на себя, но в нижнем регистре. Если мы запускаем строки в файлах до и после и ищем имена файлов, то оба, похоже, внесли одинаковые изменения. Однако, если мы запустим diff для файлов, созданных двумя циклами (diff firstloop / file1 secondloop / file1), он сообщит, что они различаются.

Это выполняется из скрипта bash в linux.

Ответы [ 3 ]

17 голосов
/ 05 августа 2011

Оболочка не выполняет подстановку переменных для строк в одинарных кавычках. Итак, вторая программа - другая.

4 голосов
/ 21 сентября 2013

Как и в других ответах, оболочка не заменяет переменные внутри одинарных кавычек, поэтому вторая версия выполняет буквальный оператор Perl s{(?i)$file_ref}{$file_ref}g для каждой строки в каждом файле.

Как вы сказали вкомментарий, если $ является метасимволом конца строки, $file_ref никогда не сможет ничего соответствовать.$ соответствует символу новой строки в конце строки, поэтому следующим символом должен быть символ новой строки.Следовательно, Perl не интерпретирует $ как метасимвол;он интерпретирует его как начало интерполяции переменной.

В Perl переменная $file_ref равна undef, которая при интерполяции обрабатывается как пустая строка.Таким образом, вы действительно выполняете s{(?i)}{}g, в котором говорится, чтобы заменить пустую строку пустой строкой, и сделать это для всех вхождений без учета регистра.Ну, есть пустая строка между каждой парой символов, плюс один в начале и конце каждой строки.Perl находит каждый и заменяет его пустой строкой.Это не вариант, но он дорогой, поэтому время работы 3 часа.

Возможно, вы ошибаетесь, что обе версии вносят одинаковые изменения.Как я только что объяснил, версия с одинарными кавычками - это просто дорогостоящий запрет;он не вносит никаких изменений в содержимое файла (он просто создает новую копию каждого файла).Файлы, на которых вы его запускали, уже должны быть преобразованы в нижний регистр.

1 голос
/ 05 августа 2011

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

Возможно, вы захотите записать весь лот в Perl или Bash, чтобы ускорить процесс.вверх.Оба языка могут читать файлы и выполнять сопоставление с образцом.В Perl вы можете перейти на строчные буквы, используя встроенную функцию lc, а в Bash 4 вы можете использовать ${file,,}.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...