强制在反引号中进行大括号扩展或者为什么这不一致?

forcing brace expansion in backticks or why is this inconsistent?

当使用反引号(在 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 下它不会

现在,经过您的多次编辑,我了解到您可能使用了两种不同的 shell。而且,调用 shell 的是 perl,不是你。

所以,覆盖三个要素:

bash

在bash。一个简单的{a}不会展开:

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

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

ls 将其作为文件进行搜索,但未找到。

手册 man bash 的相关部分是(强调我的):

A correctly-formed brace expansion must contain unquoted opening and closing braces, and at least one unquoted comma or a valid sequence expression.

{a} 缺少必需的逗号。

唯一的选择是实际使用

$ print `ls -d ~/a`

tcsh

tcsh中:一个简单的{a}将被扩展(如在csh shell中):
使用 > 作为 tcsh 提示的 shell 指标:

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

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

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

$ echo --{}++
 --++

唯一 不会 删除的大括号是 {}{ 以及 }
IIF(当且仅当)它们被识别为 "words"。最常被空格包围:

$ echo --{}++ == {} .. { :: } aa { bb
--++ == {} .. { :: } aa { bb

如果 {} 显示为单词的 部分 ,没有匹配的大括号,则为错误:

> 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.

一个额外的变化,/bin/sh 在大多数 linux 系统中由 bash 服务,由 tcsh in FreeBSD and by ksh or csh in OpenBSD

很难预测名为 /bin/sh 的 perl 的输出。

您可以确保调用特定的 shell:

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

现在问题仍然存在:

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

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

Bash:

$ 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 以不同方式扩展 glob。来自 bash docs:

A correctly-formed brace expansion must contain unquoted opening and closing braces, and at least one unquoted comma or a valid sequence expression. Any incorrectly formed brace expansion is left unchanged.

来自 tcsh docs 有点欠缺,因为它没有提到您不需要逗号进行扩展:

The metanotation 'a{b,c,d}e' is a shorthand for 'abe ace ade'. Left-to-right order is preserved: '/usr/source/s1/{oldls,ls}.c' expands to '/usr/source/s1/oldls.c /usr/source/s1/ls.c'. The results of matches are sorted separately at a low level to preserve this order: '../{memo,*box}' might expand to '../memo ../box ../mbox'. (Note that 'memo' was not sorted with the results of matching '*box'.) It is not an error when this construct expands to files which do not exist, but it is possible to get an error from a command to which the expanded list is passed. This construct may be nested. As a special case the words '{', '}' and '{}' are passed undisturbed.

现在,在 Perl 中,反引号使用 /bin/sh。当您启动 perl 进程时,它并不关心您在哪个 shell 中。来自 perlop:

A string which is (possibly) interpolated and then executed as a system command with /bin/sh or its equivalent.

这就是您看到 bash 行为的原因。但是,您可以使用任何您喜欢的 shell(并且在系统上可用):

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