为什么bash4会以不同的方式扩展花括号?

7

其中一个旧系统已升级到bash4,大部分脚本都无法工作。我已将其缩小为如何在 <(cmdA ...|cmdB ... file{1,2}|cmdZ ...) 内展开花括号。

为了更好地说明区别:

之前 (bash 3.2.25):

[root@host1:~]$ bash -version|head -1
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
[root@host1:~]$ cat <(echo sort file{1,2})
sort file1
sort file2
[root@host1:~]$ join <(sed 's/\r//g;s/^[^:]*://' file{1,2}|LANG=C sort)
[root@host1:~]$

在bash 4.1.2之后:

[root@host2:~]$ bash --version|head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
[root@host2:~]$ cat <(echo sort file{1,2})
sort file1 file2
[root@host2:~]$ join <(sed 's/\r//g;s/^[^:]*://' file{1,2}|LANG=C sort)
join: missing operand after `/dev/fd/63'
Try `join --help' for more information.
[root@host2:~]$ 

这是一个为bash4硬编码的(并且是预期的)更改吗?还是这种扩展的行为由一些bash级别的设置控制(比如set -B/set +B),可以切换回旧版/遗留版/bash3模式?我宁愿更改一些整个shell的开关(而不是必须重写一堆脚本)。
如果这个(bash3)“特性”在bug修复或改进过程中被削减了,我感到惊讶,因为旧的(bash3)语法允许节省大量打字...

3
等一下,你希望生成两个不同的“过程替换”,而不是将它们作为sed的两个参数?我不知道这是否符合正确的、有文档支持的行为……也就是说,据我所知,你的代码依赖于一个错误。 - Charles Duffy
@CharlesDuffy - 对我和脚本而言,这一直是有效的方式,直到bash4升级为止 - <(cmd {a,b}) 扩展为两个 <(cmd a) <(cmd b) 并传递给join等。这些脚本广泛使用此功能,将其嵌套到多个级别和脚本中进行测试(不想用我的粗手指触摸它并生成新错误)。 - Vlad
3
@Vlad,这似乎是一个错误,已经在Bash 4中进行了修复。您应该期望<(...)内部的命令被解析为与任何其他命令相同,因此<(cmd {a,b})应等同于<(cmd a b) - Barmar
1
这种误解是我欣赏Clojure中Rich Hickey策略的其中一点,明确而响亮地宣称:虽然已记录的功能具有向前兼容性保证,但绝不能依赖未记录的行为。 - Charles Duffy
1个回答

5
原本的行为没有文档说明(并且与在进程替换中包含的代码应该像子shell或者类似上下文一样解析的一般规则相反)。
因此,这是一个缺陷而不是一个特性。这个缺陷在bash-4.0-alpha中得到了修复。引用CHANGES条目:
rr. 花括号扩展现在允许进程替换以不变的方式通过。
没有运行时标志可用于撤消此更改。

1
我同时在挖掘同一个方向,发现另一个受影响的用户(http://wiki.bash-hackers.org/syntax/expansion/brace),然后在CHANGES中找到了相同的条目以及所有导致“commit bash-20080724 snapshot”的git提交。为了简化我的目标 - 我将重新编译自定义bash4以适应我的框,同时只回滚优先级更改,然后将重新检查脚本。遗憾的是它没有暴露给运行时标志来简化我的目标。让我点赞所有答案并感谢您! - Vlad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接