删除shell脚本(POSIX)中的最后一个参数

删除shell脚本(POSIX)中的最后一个参数,shell,sh,posix,Shell,Sh,Posix,我目前正在开发一种旨在编译成POSIX外壳语言的语言,我想介绍一种pop特性。就像使用“shift”删除传递给函数的第一个参数一样: f(){ 转移 printf'%s'$*“ } f 1 2 3#=>2 3 我想要一些代码,在下面介绍时可以删除最后一个参数 g(){ #流行音乐 printf'%s'$*“ } G23#=>12 我知道在()中详细介绍的数组方法,但是我想要一种至少能在以下shell中工作的可移植的方法:ash、dash、ksh(Unix)、bash和zsh。我还想要一些速度

我目前正在开发一种旨在编译成POSIX外壳语言的语言,我想介绍一种
pop
特性。就像使用“shift”删除传递给函数的第一个参数一样:

f(){
转移
printf'%s'$*“
}
f 1 2 3#=>2 3
我想要一些代码,在下面介绍时可以删除最后一个参数

g(){
#流行音乐
printf'%s'$*“
}
G23#=>12

我知道在()中详细介绍的数组方法,但是我想要一种至少能在以下shell中工作的可移植的方法:ash、dash、ksh(Unix)、bash和zsh。我还想要一些速度合理的东西;打开外部进程/子shell的东西对于小参数计数来说太重了,我想如果你有一个创造性的解决方案,我不介意看到它(它们仍然可以用作大参数计数的后备方案)。与那些数组方法一样快的方法是理想的。

这是我目前的答案:

pop(){
本地n=$($1-${2:-1}))
如果[-n“$ZSH_版本”-o-n“$BASH_版本”];则
POP_EXPR='set--“${@:1:'$n'}”
elif[$n-ge 500];然后
POP|EXPR=“set--$(seq-s”“1$n|sed's/[0-9]\+/“${\0}”/g”)”
其他的
本地索引=0
局部参数=“”
而[$index-lt$n];则
索引=$((索引+1))
arguments=“$arguments\”\${$index}”
完成
POP_EXPR=“set--$arguments”
fi
}
请注意,
local
不是POSIX,但是由于所有主要的
sh
shell都支持它(特别是我在问题中要求的那些shell),并且没有它可能会导致严重的bug,因此我决定将它包含在这个引导函数中。但这里有一个完全兼容的POSIX版本,带有模糊参数,以减少出现bug的可能性:

pop(){
__pop_n=$($1-${2:-1}))
如果[-n“$ZSH_版本”-o-n“$BASH_版本”];则
POP_EXPR='set--“${@:1:'$\u POP_n'}”
elif[$\u pop\n-ge 500];然后
POP\u EXPR=“set--$(seq-s”“1$\u POP\u n | sed's/[0-9]\+/“${\0}”/g”)
其他的
__pop_指数=0
__pop_arguments=“”
而[$\u pop\u index-lt$\u pop\u n];则
__pop_指数=$((pop_指数+1))
__pop\u arguments=“$\uU pop\u arguments\”\${$\uU pop\u index}”
完成
POP_EXPR=“设置--$\uu POP_参数”
fi
}
用法
pop1(){
流行音乐$#
评估“$POP_EXPR”
回显“$@”
}
pop2(){
流行音乐$#2
评估“$POP_EXPR”
回显“$@”
}
pop1 a b c#=>a b
pop1$(seq 1 1000)#=>1。。999
pop2$(seq 1 1000)#=>1。。998
下一个 使用POP创建
POP_EXPR
变量后,可以使用以下命令 函数将其更改为省略其他参数:

pop_next(){
如果[-n“$BASH_版本”-o-n“$ZSH_版本”];则
本地np=“${POP_EXPR##*:}”
np=“${np%\}*}”
POP_EXPR=“${POP_EXPR%:*}:$((np==0?0:np-1))}”
返回
fi
POP\U EXPR=“${POP\U EXPR%\”*}”
}
pop_next
是比posix shell中的
pop
简单得多的操作(尽管它是 比zsh和bash上的
pop
稍微复杂一些)

它是这样使用的:

main(){
流行音乐$#
下一个
评估“$POP_EXPR”
}
主1 2 3#=>1
POP_EXPR和变量范围 请注意,如果您不打算在之后立即使用
eval“$POP_EXPR”
pop
pop\u next
,如果您对某些函数调用的作用域不小心 在这两个操作之间,可能会更改
POP_EXPR
变量并弄乱事情 向上的为了避免这种情况,只需在每个函数的开头添加
local POP_EXPR
如果可用,则使用
pop

f(){
本地流行音乐
流行音乐$#
g 1 2
评估“$POP_EXPR”
printf“%s”f=$*“
}
g(){
本地流行音乐
流行音乐$#
评估“$POP_EXPR”
printf“%s”,g=$*“
}
f a b c#=>g=1,f=a b
popgen.sh 这个特殊的函数对于我来说已经足够好了,但是我确实创建了一个 脚本生成进一步优化的函数

在不使用外部工具的情况下提高性能的方法之一是 要认识到有几个小字符串串联是很慢的,那么 它们分批使用使功能大大加快。调用脚本
popgen.sh-gN1、N2、N3
创建一个处理操作的pop函数 根据参数计数,以N1、N2或N3批为单位。剧本也 包含其他技巧,举例说明如下:

$sh popgen\
>-g 10100 \#成批连接字符串\
>-w\#覆盖当前文件\
>-x9 \#硬编码前9个参数计数的结果\
>-t1000 \#从参数计数1000开始,使用外部工具\
>-p posix \#要添加到函数名的前缀(带下划线)\
>要添加到函数名的-s“”后缀(带下划线)\
>-c \#使用命令popsh代替seq/sed作为外部工具\
>-@\#在zsh和bash上,使用子数组方法(运行时检查)\
>-+\\使用bash/zsh扩展(从-@中删除运行时检查)\
>-nl \#不要使用“本地”\
>-f \#使用“函数”语法\
>-o pop.sh#输出文件
可以使用
popgen.sh-t500-g1-@
生成与上述函数等效的函数。 在包含
popgen.sh
的要点中,您将找到一个
popsh.c
文件,该文件可以 编译并用作默认shell的专用、更快的替代方案 外部工具,它将被生成的任何函数使用
popgen.sh-c…
如果shell可以通过
popsh
访问它。 或者,您可以创建名为
popsh
的任何函数或工具并使用 取而代之的是它

基准 基准功能: 我用于基准测试的脚本可以在以下要点中找到:

基准函数可在以下行中找到:

脚本可以这样使用:

$sh popbench.sh\
>-s dash \#基准使用的shell,可以是das