Perl однострочник Windows 10 / Power Shell: заменить строку в нескольких файлах, заканчивающуюся *. sql, не будет работать (* глобирование не распознается) - PullRequest
2 голосов
/ 03 апреля 2020

Следующий однострочный оператор Perl не работал при использовании "*" globbing:

>>> perl -i'.bak' -pe 's#__SUB__CWD__#'$(pwd)'#g' *.sql
Can't open *.sql: Invalid argument. 

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

>>> perl -p -i'.bak' -e 's#__SUB__CWD__#'$(pwd)'#g' A_SINGLE_FILE.sql

Любая идея, которая может заставить perl понять, что "*" должна быть прочитана в формате REGEX?

Я пытаюсь заменить все вхождения " SUB__CWD"."в тоннах файлов.

C .f. https://github.com/oracle/db-sample-schemas/blob/master/README.md

Ответы [ 2 ]

4 голосов
/ 03 апреля 2020

Это не ошибка Perl, а Windows. Linux оболочки расширяют подстановочные знаки для вас, cmd.exe нет. Я не знаю, что такое PowerShell, но, похоже, и этого нет.

Кроме того, вы не хотите интерпретировать звездочку как регулярное выражение, а как шаблон с глобусом. В регулярном выражении * означает «предыдущая вещь должна повторяться ноль или более раз».

Вы можете использовать Perl s glob function:

perl -p -i'.bak' -e 'BEGIN {@ARGV = glob shift} s#__SUB__CWD__#'$(pwd)'#g' *.sql

Обратите внимание, что вам нужно использовать обратную косую черту sh в пути, чтобы Perl не мог их интерпретировать, т. Е. Используйте $($pwd -replace '\\', '\\') вместо $(pwd). Вам также необходимо поставить в обратном порядке sh # символы в пути, так как в противном случае они будут пониматься как разделители, поэтому используйте $($pwd -replace '[\\#]', '\$&').

Поэтому было бы даже чище не использовать $(pwd), но пусть Perl знает, что такое замена:

perl -p -i'.bak' -e 'BEGIN{ ($pwd, @ARGV) = (shift, map glob, @ARGV) }
                   s/__SUB__CWD__/$pwd/g' -- $(pwd) *.sql

Первый аргумент присваивается $pwd через shift , остальные атрибуты отображаются в glob, что означает Вы можете указать более одного шаблона подстановки.

3 голосов
/ 03 апреля 2020

ответ Чоробы предоставляет хорошие указатели и решения, ориентированные больше на perl стороны.

A прямая адаптация вашей команды к PowerShell на Windows есть (Windows PowerShell и PowerShell [Core]):

perl -i'.bak' -pe "s#__SUB__CWD__#$($pwd -replace '[\\#]', '\$&')#g" (Get-ChildItem *.sql).Name

Как указывает Чороба, PowerShell на Windows делает не делает глобирование (расширение шаблонов подстановочных знаков для соответствия именам файлов) для вас; однако, он работает на Unix -подобных платформах - см. ниже.

  • (Get-ChildItem *.sql).Name использует командлет Get-ChildItem для выполнения подстановки вручную.

  • $pwd -replace '[\\#]', '\$&' использует основанный на регулярных выражениях PowerShell оператор -replace , чтобы обеспечить как разделители пути \ в пути текущего каталога, так и любые # символы \ -экранированы, чтобы гарантировать, что \ не интерпретируется как начало escape-последовательности функцией Perl s, а # не неверно истолкован как символ-разделитель.

Для PowerShell [Core] на Unix -подобных платформах (macOS, Linux) :

По сути, ваша команда будет работать как есть - до тех пор, пока текущий путь к каталогу не содержит пробелов (что повлияет на вашу команду в POSIX-подобных оболочках, таких как bash тоже).

Следующий вариант решает эту проблему:

# PowerShell [Core] on macOS and Linux
# If the current-directory path contains '#' chars.,
# use the -replace operation shown above.
perl -i'.bak' -pe "s#__SUB__CWD__#$(pwd)#g" *.sql

Примечание: $($pwd) будет несколько более эффективным потому что он использует автоматическую c $PWD переменную вместо команды pwd , псевдоним для командлета Get-Location.

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