Perl一行式Windows10/PowerShell:替换多个文件中以*.sqlwon'结尾的字符串;不起作用



以下一行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

这不是Perl的错,而是Windows的错。Linux shell会为您扩展通配符,cmd.exe不会。我不知道PowerShell,但似乎也不知道。

此外,您不想用正则表达式的方式来解释星号,而是用glob模式的方式。在正则表达式中,*的意思是"前一件事应该重复零次或多次"。

您可以使用Perl的glob函数:

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

请注意,您需要在路径中反斜杠以防止Perl解释它们,即使用$($pwd -replace '\', '\')而不是仅使用$(pwd)。您还需要对路径中的#字符进行反斜杠,否则它们将被理解为分隔符,因此请使用$($pwd -replace '[\#]', '$&')

因此,如果不使用$(pwd),而是让Perl知道替换是什么,那就更干净了:

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

第一个参数通过shift分配给$pwd,其余属性映射到glob,这意味着您可以指定多个通配符模式。

choroba的回答提供了很好的指针和解决方案,更侧重于perl方面。

将命令直接适配到Windows上的PowerShell是(Windows PowerShell和PowerShell[Core](:

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

正如choroba所指出的,Windows上的PowerShell不会为您执行globbing(将通配符模式扩展到匹配的文件名(;然而,它在类Unix平台上确实如此——请参阅下文。

  • (Get-ChildItem *.sql).Name使用Get-ChildItemcmdlet手动执行globbing。

  • $pwd -replace '[\#]', '$&'使用PowerShell基于正则表达式的-replace运算符来确保当前目录路径中的路径分隔符以及任何#字符都是转义符,以确保不会被Perls函数解释为转义序列的开始,并且#不会被误解为分隔符。

对于类Unix平台上的PowerShell[Core](macOS、Linux(

从本质上讲,只要当前目录路径不包含空格(这也会影响您在类似POSIX的shell(如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)的效率稍高,因为它使用自动$PWD变量,而不是pwd命令(Get-Locationcmdlet的别名(

最新更新