强制支撑在反推中扩展或为什么这种不一致?

时间:2017-05-16 10:17:31

标签: linux bash perl shell tcsh

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

2 个答案:

答案 0 :(得分:8)

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

所以,要涵盖这三个要素:

的bash

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

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

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

ls搜索为文件,但未找到。

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

  

正确形成的大括号扩展必须包含未加引号的开启和关闭大括号,并且至少包含一个未加引号的逗号或有效的序列表达式。

{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

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

> 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 FreeBSDksh or csh in OpenBSD

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

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

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

现在问题仍然存在:

  • 为什么需要在单个角色上使用大括号扩展?

答案 1 :(得分:2)

当您遇到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

TSCH:

% 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。来自bash docs

  

正确形成的大括号扩展必须包含不带引号的开括号和右大括号,以及至少一个不带引号的逗号或有效的序列表达式。任何不正确形成的支撑扩展都保持不变。

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

  

metanotation'a {b,c,d} e'是'abe ace ade'的简写。保持从左到右的顺序:'/ usr / sources / s1 / {oldls,ll}}'扩展为'/usr/source/s1/oldls.c /usr/source/s1/ls.c'。匹配结果在低级别单独排序以保留此顺序:'../ {memo,* box}'可能会扩展为'../memo ../box ../mbox'。 (请注意,'memo'未按匹配'* box'的结果排序。)当此构造扩展为不存在的文件时,这不是错误,但是可能从命令中获取错误扩展列表已通过。这个结构可以嵌套。作为一种特殊情况,单词“{”,“}”和“{}”不受干扰地传递。

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

  

一个字符串,它(可能)被内插,然后作为系统命令用/ bin / sh或它的等价物执行。

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

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