GNU查找并掩盖了某些shell的{}-哪个?


34

GNU查找手册页指出:

-exec command ;
    [...] The  string `{}'  is  replaced  by the current 
    file name being processed everywhere it occurs in the 
    arguments to the command, not just in arguments where 
    it is alone, as in some  versions  of  find.
    Both  of  these  constructions might need to be escaped 
    (with a `\') or quoted to protect them from expansion 
    by the shell. 

那是从男人到find(GNU findutils)4.4.2。

现在,我使用bash和dash进行了测试,并且两者都不需要{}被遮盖。这是一个简单的测试:

find /etc -name "hosts" -exec md5sum {} \; 

是否有我确实需要遮盖牙套的外壳?请注意,这并不取决于找到的文件是否包含空白(从bash调用):

find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \; 
/home/stefan/Ubuntu One

如果将找到的文件传递到子shell,则此更改:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \; 
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory

可以通过以下方法解决:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;

与:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \; 
/home/stefan/Ubuntu One

但这不是手册页在谈论的,是吗?那么,哪个外壳{}以不同的方式对待?


@Volker Siegel:您的编辑可能是出于善意,但我检查了当前的查找手册,而您的更正是错误的,您也错过了总结您的编辑的机会,这是一个坏习惯,所以我撤消了所做的更改。抱歉,老兄
用户未知

哦,谢谢您回滚它,如果它坏了。我还记得文本编译器生成手册页格式的过程,该手册页格式用于生成这些“印刷报价”,作为渲染定义的工件。它还可以渲染到TeX以获得完美的打印输出格式。我注意到引号,因为它们使语法突出显示感到困惑。我假设在代码中使用时,异常的第一引号是错误的,并且仍然假设是。请注意,这两个更改是在描述文本中,而不是代码中。因此,如果我们将它们视为版式-美学渲染-那就对了。
Volker Siegel '18

看起来像在信息输出渲染中,两边使用相同的引号。毫无疑问,我的更改使它与原始更改有所不同,您是对的。但这有什么问题吗?(据我所知,第一个引号是人工渲染定义中的错误,据我所知,这是唯一的版式。)
Volker Siegel,

我刚刚检查过:“ {}”在命令行上不起作用。从技术上讲,这是正确的,但我不喜欢毫无戒心的用户在尝试复制和粘贴该错误时会遇到一个奇怪的错误。
Volker Siegel '18

@VolkerSiegel:它是散文,而不是代码,那么用户应在此处复制粘贴什么?这是2011年手册页的引文。我看不出任何更正段落的价值,然后指出了为什么对手册页进行了更正。这个话题很复杂。如果这是您的问题,我不会说服您,准确地引用手册页,但是对于我的问题,我不打算妥协。引用就是引用。
用户未知

Answers:


26

简介:如果有一个可扩展的外壳{},那么到目前为止,它确实是旧的旧东西。

在Bourne shell和在POSIX兼容的外壳,括号({})是普通字符(不像()它是字分隔符像;&,以及[]它们的通配符)。以下所有字符串均应按原样打印:

$ echo { } {} {foo,bar} {1..3}
{ } {} {foo,bar} {1..3}

由单个花括号组成的单词是保留单词,仅当它是命令的第一个单词时才是特殊的。

Ksh将括号扩展实现为对Bourne shell的不兼容扩展。可以用关闭set +B。Bash在这方面模仿ksh。Zsh还实现了括号扩展;可以用set +Isetopt ignore_braces或将其关闭emulate sh。这些外壳程序{}在任何情况下都不会扩展,即使它是单词的子字符串(例如foo{}bar),也由于它们在find和参数中的常用用法而不会扩展xargs

单个Unix v2指出

在某些历史系统中,花括号被视为控制运算符。为了协助将来的标准化活动,便携式应用程序应避免使用不带引号的花括号来表示字符本身。ISO / IEC 9945-2:1993标准的未来版本可能会要求这样做,{并被}单独视为控制运算符,尽管{}由于经常使用的find {}结构,令牌可能会在此情况下成为特殊情况的豁免。

该注释已在标准的后续版本中删除;的示例find具有的未引用用途{},例如的示例也是如此xargs。可能有{}必须引用的Bourne历史外壳,但到现在为止它们确实是旧的旧系统。

我手头的csh实现(OpenBSD 4.7,Debian上的BSD csh,tcsh)都扩展{foo}到了,foo{}别说了。


1
@geekosaur:markdown中只有一小部分在评论中起作用。我不知道你想说什么。如果这是关于ksh等人的大括号扩展的,请阅读我的段落,开头为“ Ksh将大括号扩展实现为不兼容的扩展”。
吉尔(Gilles)“所以,别再邪恶了”,

2
那是bash(请参阅参考资料$BASH_VERSION)。支撑扩展非常有效。
geekosaur 2011年

2
就是重点。该{}语法起源于csh,而是{}扩展为空字符串。较新的shell认为这是荒谬的,但是仍然有一些旧csh的。
geekosaur 2011年

1
@geekosaur:您能说说在哪个特定平台上的哪个特定csh版本吗?我宁愿自己进行测试(如果可以在linux上进行测试),也可以放心,该人自己进行测试。
用户未知,

1
@geekosaur,{}foo将扩展为foo,但{}将扩展为{}(除非在反引号内,但引用无济于事),因此已被记录下来。我已针对2BSD(第一版),2.79BSD,2.8BSD和2.11BSD的csh对其进行了验证。
斯特凡Chazelas

12

{}需要的版本被引用fish之前3.0.0外壳。

$ fish -c 'echo find -exec {} \;'
find -exec  ;

并且在rc shell中(也akanga基于rc,但不是es):

$ rc -c "echo find -exec {} ';'"
line 1: syntax error near '{'

这些可能不是该GNU查找文档的作者在编写该文本(自fish2005年首次发布以来,该文本或类似内容于1994年就已经存在)以来rc所想到的外壳,并且最初不是Unix shell。

有传言称某些版本的csh(引入括号扩展的外壳)需要它。但是,由于csh2BSD 的第一个版本没有发布,所以很难赞扬这些。如在PDP11仿真器中测试的:

# echo find -exec {} \;
find -exec {} ;

2BSDcsh手册页明确指出

作为一种特殊情况,“ {”,“}”和“ {}”不受干扰地传递。

因此,如果后来的csh或tcsh版本破坏了它,我会感到很奇怪。

可能是为了解决某些版本中的某些错误。仍然使用2BSD csh(在2.79BSD,2.8BSD,2.11BSD中相同):

# csh -x
# echo foo {} bar
echo foo {} bar
foo {} bar
# echo `echo foo {} bar`
echo `echo foo {} bar`
echo foo {} bar
foo  bar

引用无济于事:

# echo `echo foo '{}' bar`
echo `echo foo '{}' bar`
echo foo {} bar
foo  bar

您可以引用整个命令替换:

# echo "`echo foo {} bar`"
echo `echo foo {} bar`
echo foo {} bar
foo {} bar

但这给外部回声传递了一个论点。

csh或中tcsh,您需要{}像这样单独引用when:

find . -name '*.txt' -type f -exec cp {} '{}.back' \;

(尽管这种find用法是不可移植的,因为有些用法find只有{}在自己扩展时才会扩展)。


1

一言以蔽之cshbash和其他现代Shell都意识到用户可能并不需要大括号扩展。(csh实际上是现代的,tcsh并且{}到现在也可能理智地处理。)


很高兴听到您的声音,但是我要的是相反的要求,一个不能明智地处理它的外壳。
用户未知

您假设某人会因为Linux系统都具有较新的版本而进入并删除信息页面对额外报价的引用csh。并非每个人都在Linux上运行GNU实用程序。实际上,将它们安装在捆绑命令受限制的较旧的商用Unix系统上是很普遍的。(csh在这些系统上替换的可能性较小,因为系统脚本可能依赖于原始系统的特性csh,即使用户都配置为使用更新的系统cshroot也几乎肯定需要保留捆绑的版本。)
geekosaur 2011年

2
否。我正在与一个人辩论,他说,在我们的Wiki中,我们应该始终建议您使用“ {}”,因为手册页上是这样说的。现在,我想知道是否有一个我不使用的外壳,例如ksh,zsh,tcsh,csh或XYZsh,但我不知道该声明是否正确,或者我是否可以假定,没有。如果有用于不同Unix的shell需要“ {}”,那将很好地解释了为什么该句子仍在手册页中,但不适用于Linux初学者的建议。
用户未知

现在,我想知道如果pdksh做正确的事......虽然正确答案很可能是“真正ksh是FOSS这些天”。
geekosaur 2011年

4
像mksh,ksh93,bash和zsh一样,pdksh仅在两者之间有逗号(或..ksh93,bash和zsh)时才展开花括号。只有(t)csh会扩展{foo}foo,甚至它都{}单独存在(至少在最近的BSD上如此)。
吉尔斯(Gilles)'所以
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.