perl 在反勾号中强制大括号扩展,或者为什么这不一致?

a8jjtwal  于 2022-11-15  发布在  Perl
关注(0)|答案(2)|浏览(284)

当使用反勾号(在perl中)时,我似乎与大括号扩展有某种不一致。

print `ls -d ~/{a,b}`;

工作正常,但当我尝试

print `ls -d ~/{a}`;

我得到:

ls: cannot access /home/user/{a}: No such file or directory

我试过各种引用、空格和转义,但都没有用。我的问题是,有没有办法强制扩展?我意识到如果我自己把这些东西弄混,我可以一起避免这个问题,但我对这种行为很好奇
我在bash和tcsh下都试过了。当直接在tcsh下使用时,该命令可以工作,但在bash下不能

ctehm74n

ctehm74n1#

现在,经过你的几次编辑,我明白你可能使用了两个不同的shell。而且,调用shell的是Perl,而不是你。
所以,要涵盖三个要素:

狂欢

在bash中。简单的{a}将不会展开:

$ echo ~/{a,b}
/home/user/a /home/user/b

$ echo ~/{a}
/home/user/{a}

ls将其作为文件进行搜索,但未找到。
手册的相关部分是(强调我):
格式正确的大括号扩展必须包含不带引号的左大括号和右大括号,以及至少一个不带引号的逗号或有效的序列表达式。
{a}缺少必需的逗号。
唯一的选择就是

$ print `ls -d ~/a`

tcsh命令

tcsh中:将展开简单的{a}(如同在csh shell中):
使用>作为tcsh提示符的shell指示符:

> echo --{a,b}++
 --a++ --b++

> echo --{a}++
--a++

作为一个简单的{}也将:

$ echo --{}++
 --++
    • 不会**删除的括号只有{}{}
  • IIF*(当且仅当)它们被识别为“单词”。最常见的是被空格包围:
$ echo --{}++ == {} .. { :: } aa { bb
--++ == {} .. { :: } aa { bb

如果{}作为单词的 part 出现,但没有匹配的大括号,则为错误:

> echo aa{bb
Missing '}'.

man tcsh上对此的唯一描述非常简短(不清楚?):

> As a special case the words `{', `}' and `{}' are passed undisturbed.

Perl语言

如果shell命令是called from perl,则在调用shell的情况下(如在Unix系统下),调用的shell是/bin/sh
另一个变化是,在大多数linux系统中,/bin/sh由bash、tcsh in FreeBSDksh or csh in OpenBSD提供服务。
很难预测一个名为/bin/sh的perl的输出。
您可以确保特定shell的名称为:

#!/usr/bin/perl
print `/bin/tcsh -c 'ls -d ~/{a,b}'`;

现在的问题是:

  • 为什么需要对单个字符使用大括号扩展?
eh57zj3b

eh57zj3b2#

当您在使用shell命令时遇到问题时,请在Perl(或任何程序)之外尝试使用这些命令,看看它们的作用:
猛击:

$ ls ~/{a}
ls: /Users/brian/{a}: No such file or directory
$ ls ~/{a,b}
ls: /Users/brian/a: No such file or directory
ls: /Users/brian/b: No such file or directory

切:

% ls ~/{a}
ls: /Users/brian/a: No such file or directory
% ls ~/{a,b}
ls: /Users/brian/a: No such file or directory
ls: /Users/brian/b: No such file or directory

因此,您可以看到这两个shell以不同的方式展开globs。
格式正确的大括号扩展必须包含不带引号的左大括号和右大括号,以及至少一个不带引号的逗号或有效的序列表达式。任何格式不正确的大括号扩展都将保持不变。
tcsh docs是一个有点缺乏,因为它没有提到,你不需要逗号的扩展:
元表示法“a{B,c,d}e”是“abe ace ade”的简写。从左到右的顺序被保留:“/usr/source/s1/{oldls,ls}.c”扩展为“/usr/source/s1/oldls.c/usr/source/s1/ls.c”。匹配结果在较低级别单独排序,以保留以下顺序:.."/{备忘录,* 框}“可能会扩展为..”/备忘录../框../mbox“。(请注意,'memo'没有使用匹配'* box'的结果进行排序。)当此构造展开到不存在的文件时,这不是错误,但可能会从向其传递展开列表的命令中获取错误。此构造可能是嵌套的。作为特殊情况,单词'{',“}”和“{}”不受干扰地传递。
现在,在Perl中,反勾号使用 /bin/sh,它不关心您在哪个shell中启动 perl 进程。
一个字符串,它(可能)被插入,然后作为系统命令与/bin/sh或其等效命令一起执行。
这就是为什么你会看到bash行为。但是,你可以使用任何你喜欢的shell(并且在系统上可用):

my $output = `tcsh -c 'ls -l ~/{a}'`

相关问题