sh shell不支持$ @上的参数扩展吗?


8

我在AU上发布一个问题的答案,我发现on的参数扩展$@不适用于shshell:

<infile xargs -d'\n' sh -c 'echo "${@%%/*}"' _

但它在中工作正常bash。这是sh外壳程序的预期行为吗,我如何在该处执行扩展?

此外,我知道使用-n1选项xargs我一次只能向命令传递一行,但是我对是否sh可以扩展很感兴趣$@

<infile xargs -d'\n' -n1 sh -c 'echo "${0%%/*}"'

infile 包含:

A1 /B1/C1
A 2/B2/C2
A3/B3/C3

Answers:


12

是的,破折号似乎在这里没有用。虽然它是没有过错的,严格来说,作为${@%...}不确定的POSIX

以下四种参数扩展提供了子字符串处理。[...]如果参数为“ #”,“ *”或“ @”,则扩展结果不确定。

但是,这很奇怪,如果像这样的扩展修改了一个位置参数的结尾,它将删除以下位置参数。但是,如果它实际上没有修改结尾,则不会:

$ dash -c 'set -- foo bar; printf "<%s>\n" "${@%o}";'
<fo>
$ dash -c 'set -- foo bar; printf "<%s>\n" "${@%x}";'
<foo>
<bar>
$ dash -c 'set -- foo bar doo; printf "<%s>\n" "${@%r}";'
<foo>
<ba>

Bash,ksh和Zsh似乎都可以处理"${@#...}""${@%...}"通过独立处理每个位置参数来完成,这似乎很有用。

我想明显的解决方法dash是一次使修改一个参数:

for x in "$@"; do echo "${x%%/*}"; done

值得的是,$*shell之间使用的前缀/后缀删除扩展的行为也有所不同。Bash和ksh似乎先修改参数,然后再将它们联接,而Zsh和dash首先联接参数并修改串联字符串:

$ zsh -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a>
$ bash -c 'set -- ax bx; printf "<%s>\n" "${*%%x*}";'
<a b>

听起来sh认为$@是整个文件的单个参数(或将打破多个,如果超过ARG_MAX)和做的唯一理由扩张。
αғsнιη

1
还要注意,pdksh和派生类会使您Bad substitution在该代码上出错。对于${*%pattern},你看到在行为之类的一些变化"$shell" -c 'printf "<%s>\n" "${*%x*}"' sh ax by
斯特凡Chazelas

1
@αғsнιη,不是那么简单。请注意第二个示例,其中扩展将位置参数留为单独的单词。而且我不认为其中ARG_MAX涉及到处理是外壳内部的。
ilkkachu
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.