以下一行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-ChildItem
cmdlet手动执行globbing。$pwd -replace '[\#]', '$&'
使用PowerShell基于正则表达式的-replace
运算符来确保当前目录路径中的路径分隔符以及任何
#
字符都是转义符,以确保
不会被Perl
s
函数解释为转义序列的开始,并且#
不会被误解为分隔符。
对于类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-Location
cmdlet的别名(