如何将 raku -e 和 -n 与多个文件 glob 一起使用

How do I use raku -e and -n with multiple file glob

我想在 windows

的 raku 中进行以下操作
raku -n -e ".say if /mydatabegin/;" *.file

无法打开文件 C:\..\*.file: 参数无效

glob 未被解释为 glob。我认为那是因为 windows 要求您的程序自己进行通配?那么是否有预处理指令或函数,甚至是我可能错过或重定向的开关,或者允许在保持 -n(或 -p)和 -e 开关的简单性的同时扩展 glob 的东西?

显然,我可以通过删除 -n(或 -p)将其更改为完整程序,只需使用 -e 指定一个 main,然后在 glob 结果上循环。但是我真的很喜欢-n.

PS。我真的只是在学习 raku,并且很惊讶这不是开箱即用的。因此,具有简单语法的完整程序示例也可以工作。但是我真的很喜欢-n..

编辑:回复@chenyf

raku -e ".say for $*ARGFILES" *.file

同样的错误。相关:

raku -e ".say for $*ARGFILES.lines" *.file

同样的错误。

raku -e "use IO::Glob; .say for glob('*.file')"

按预期工作!展开:

raku -e "use IO::Glob; .say for glob('*.file').lines"

'lines' 类型 'IO::Glob'

的调用者没有这样的方法

越来越接近 - 或许对此进行扩展是一个足够好的解决方法。但回到一线荣耀尝试:

raku -e "use IO::Glob; .say for glob($*ARGFILES)" test.file

无法解析调用者 glob(IO::ArgFiles:D); none 个签名匹配。

好的 - 让我们回到字符串的安全:

raku -e "use IO::Glob; .say for glob($*ARGFILES.Str)" test.file

是的!所以..:[=​​24=]

raku -e "use IO::Glob; .say for glob($*ARGFILES.Str).lines" test.file

'lines' 类型 'IO::Glob'

的调用者没有这样的方法

我显然需要阅读更多手册。但是让我们稍微退后一步,看看我的用例是否有效:

raku -e "use IO::Glob; .say for glob($*ARGFILES.Str)" *.file

无法打开文件 C:\..\*.file: 参数无效

我一开始就犯了同样的错误。这可能只是 windows 错误的 raku 吗?

编辑:

raku -MIO::Glob -e "my @files = (map { glob($_).dir }, @*ARGS).flat; for @files -> $file { say $_ for $file.lines }" *file *file2 *5

我有三套档案。我几乎可以接受这个解决方案 - 除了某些原因,这些行被打印为 "s

关于缩短和删除引号的任何想法?

编辑 解决 $*ARGFILES 变量的自动通配:

raku -MIO::Glob -n -e "BEGIN { @*ARGS = (map { glob($_) }, @*ARGS).flat }; .say" *.file *.file2

这样做的好处是仍然看起来像原来的内衬;它使用-n!它只需要在创建 $*ARGFILES 时进行通配,这似乎是一个错误。

raku -MIO::Glob -e "BEGIN { @*ARGS = (map { glob($_) }, @*ARGS).flat }; .say for $*ARGFILES.lines" *.file *.file2

上面转换为 $*ARGFILES.lines 表明 $*ARGFILES 从 @*ARGS 动态获取它的值。

编辑

最后,事实证明 glob 函数不适用于目录,至少在 windows 上是这样(documentation 有一个根本不起作用的示例)。

#Example from https://github.com/zostay/raku-IO-Glob
for glob("src/core/*.pm") -> $file { say ~$file }

#mine that doesn't work
raku -MIO::Glob -e "for glob('..\*.file') -> $file { say ~$file }"

#mine that does work.
raku -MIO::Glob -e "for glob('*.file').dir('..') -> $file { say ~$file }"

#And therefore the final modification of the script above:
raku -MIO::Glob -e "BEGIN { @*ARGS = (map { glob(.IO.basename).dir(.IO.dirname) }, @*ARGS).flat };  .say for $*ARGFILES.lines" ..\*.file

我对文件通配的基本理解是 shell 处理这个问题——而且由于您似乎在 Windows,所有的赌注都可能被取消。唯一的例外可能是如果您使用 WSL Windows-Subsystem-for-Linux,这应该会给您更多 Unix/Linux-like 体验:

https://docs.microsoft.com/en-us/windows/wsl/about

根据下面的 Microsoft 文档,Windows 有两个内置的 shells,CMD.exe 和 Powershell(我相信 WSL shell以上是可选的):

"命令Shell概述"

"Windows有两个命令shell:The Commandshell和PowerShell。每个shell是一个软件在您与操作系统或应用程序之间提供直接通信的程序,提供自动化 IT 操作的环境。"

https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/windows-commands


以下是在相当老的 bash/MacOS 系统上运行的内容。 使用 -ne(非自动打印)命令行标志:

raku -ne 'print $_ ~ "\n";'
raku -ne 'say $_ ;' 
raku -ne '.say;'

使用-pe(自动打印)命令行标志:

raku -pe 'print "";'
raku -pe ''

我实际上只是使用上面的命令打印了五 (5) 个 *.txt 文件的内容。 -e 标志始终结束您的命令行标志簇,但 可以 组合(请参阅下面的 -M 标志以了解例外情况)。

现在因为您在 Windows,您可能需要将 "" 双引号替换为 '' 单引号(反之亦然!)。但希望这能让你开始。 [任何其他问题,您可能必须指定 Rakudo 可执行文件的完整路径]。

如果您希望 Raku 为您处理目录修改,可以使用 Raku 的 dir() 命令,该命令可以与其 :test 副词(参数)结合使用。下面比较上述目录中有五 (5) 个 *.txt 个文本文件,(删除 .elems 打印实际文本的调用):

raku -e '.lines.elems.say for dir(test => / \.txt $ /);'
14
16
34
1
16

对比:

raku -e '.lines.elems.say for $*ARGFILES;' *.txt
81

https://docs.raku.org/routine/dir


附录:我对 Raku P5-to-P6 词汇表的检查表明,设计者故意将 Perl5 的 glob 功能排除在 Perl6/Raku 之外,而是选择更强大的内置 dir()套路。链接如下:

https://docs.raku.org/language/5to6-perlfunc#index-entry-glob_-_perlfunc https://docs.raku.org/routine/dir

Raku 模块 IO::Glob 是非核心的(而且..我从未尝试过)。但是如果你在命令行工作并想加载一个模块,你可以使用(例如)-MIO::Glob 后跟 -e-ne-pe 等.(此外,无需在您的 Raku 单行中加入 use IO::Glob; 行,它已经通过 -M 加载)。

在下面的链接中查看带有 Txt::CSV 模块 and/or XML 模块的 Raku 单行示例:

https://unix.stackexchange.com/search?q=%5Bcsv%5D+Raku
https://unix.stackexchange.com/search?q=%5Bxml%5D+Raku

关注下面的额外WindowsCMD.exediscussion/resolution:

https://github.com/rakudo/rakudo/issues/4550

一般答案 - 这不是错误。 Windows 如果需要,程序必须处理它们自己的 globbing。让它在 raku 可执行文件中工作对我来说很有意义;它消除了平台特定的惊喜,并使单线更容易。

但其他人不这么看,有一个足够简单的解决方案 - 创建自己的模块,以便代码保持一致并相对简单地调用。

这是一个初学者模块。有空间可以添加

之类的东西
  • 强制成功匹配的开关
  • 指示失败的 glob 应保留在 @*ARGS 变量中的开关
  • 在它之后切换到仅 glob。
  • 应用通配而不是自动执行的例程。这将允许您删除非文件开关
  • 将每个 glob 收集到自己的列表中(可能需要一个开关)。

模块:

unit module CLGlob:ver<1.0>:auth<pureabsolute>;

use IO::Glob;

@*ARGS = map { .Str }, (map { glob(.IO.basename).dir(.IO.dirname) }, @*ARGS ).flat;

注意:当 glob 函数适用于 windows 目录时,可以简化第二个映射中的表达式。

注意:我将每个元素都转换为 .Str 以使 @*ARGS 保持一致。 $*ARGFILES 无需执行此操作即可工作,因此如果您再也不会查看 @*ARGS,则可以节省一些处理。

最后,最终结果:

raku -MCLGlob -ne ".say" ..\*.file ..\*.file2

赞。