从 shell 脚本 (bash) 的参数列表中删除最后一个参数

Posted

技术标签:

【中文标题】从 shell 脚本 (bash) 的参数列表中删除最后一个参数【英文标题】:Remove last argument from argument list of shell script (bash) 【发布时间】:2013-12-22 07:19:13 【问题描述】:

这个问题涉及在 automator osx 中运行的 bash 脚本。我正在使用自动操作从查找器中获取和过滤一堆文件引用。然后,我也通过自动操作将父文件夹的名称附加到该列表中。 Automator 然后将这些参数提供给一个名为“运行 shell 脚本”的操作。我不确定 automator 究竟是如何调用脚本的,但参数列表在与以下内容相呼应时看起来像这样:echo "$@"

/Volumes/G-Raid/Online/WAV_TEST/Testbok 50/01/01000 43-001.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50/02/02000 43-002.wav /Volumes/ G-Raid/在线/WAV_TEST/Testbok 50/03/03000 43-003.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50

在这种情况下是 3 个文件和一个文件夹的路径。

在 shell 脚本中,我启动了一个名为 ripcheckc* 的应用程序,它使用从 automator 传递的参数减去列表中的最后一个参数(文件夹)。

我用它来删除最后一个参数:

_args=( "$@" )
unset _args[$#_args[@]-1]

这是echo $_args

/Volumes/G-Raid/Online/WAV_TEST/Testbok 50/01/01000 43-001.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50/02/02000 43-002.wav /Volumes/ G-Raid/在线/WAV_TEST/Testbok 50/03/03000 43-003.wav

和以前一样,但没有文件夹。

现在,如果我使用 "$@" 作为参数运行 ripcheckc,它可以工作(但由于参数列表中的最后一个路径而稍后失败)如果我使用 $_args[@],应用程序将静默中止。当我回显$@_args 时,除了最后一个参数外,输出看起来相同。

我的问题是 - 使第一个有效输入和第二个无效输入的 $@ 和 $_args 之间有什么区别?

*申请是ripcheckc

我希望我的问题有意义。

编辑:已解决。

【问题讨论】:

我用双引号解决了这个问题。像这样:ripcheckc "$_args[@]". 【参考方案1】:

假设你已经有一个array,你可以说:

unset "array[$#array[@]-1]"

例如,如果您的脚本包含:

array=( "$@" )
unset "array[$#array[@]-1]"    # Removes last element -- also see: help unset
for i in "$array[@]"; do
  echo "$i"
done

使用:bash scriptname foo bar baz 调用它会产生:

foo
bar

【讨论】:

谢谢,这是摆脱最后一个参数的更好方法。我的问题是,与 $array 相比,$@ 似乎有些不同,它将它作为我传递给它的应用程序的有效输入。我只是不知道它是什么。 @user1047256 尝试将$array[@] 传递给您的应用程序。 我尝试了你的建议,但还是不行。仅供参考,我将昵称更改为 Nordanfors。 :-) @Nordanfors 总是引用变量。 应该接受下一个答案,而不是这个。它有三倍的赞成票。【参考方案2】:

你也可以得到除最后一个参数之外的所有参数

"$@:0:$#"

老实说,这有点粗略,因为它似乎(ab)使用了参数从 1 开始编号的事实,而不是 0。

更新:这只适用于处理$@ 的错误(最迟在 4.1.2 中修复)。它适用于 3.2 版。

【讨论】:

代码 "$@:1:$#-1" 正是使完整的参数列表像 "$@" 没有最后一个的原因。 对。粗略部分使用 0 作为第一个参数,以避免必须从第二个参数中减去 1。 实际上,索引 0 包括非参数 - 正在执行的脚本的路径(shell 自动提供的值)。您并没有避免减 1 - 最后一个参数仍然包含在内,您必须减去 1。使用 0 只是在列表中再添加一个(可能不需要)值。 由于随后修复了一个错误,这似乎在 bash 3.2 中有效。【参考方案3】:

我之前用过这个bash one-liner

set -- "$@:1:$(($#-1))"

它将参数列表设置为当前参数列表,减去最后一个参数。


它是如何工作的:

$# 是参数的数量 $((...)) 是一个算术表达式,因此 $(($#-1)) 比参数数量少一。 $variable:position:count 是一个substring expression:它从variable 中提取count 字符,从位置开始。在special case 中,其中variable@,表示参数列表,它从position 开始的列表中提取count arguments。这里,position 是第一个参数的 1count 比之前计算的参数数量少一个。 set -- arg1...argn sets the argument list 到给定的参数

所以最终结果是参数列表被替换为新列表,其中新列表是除最后一个参数之外的原始列表。

【讨论】:

简洁优雅:我喜欢。我使用下面@chepner 建议的变体来“删除”前两个参数,以便正确生成子流程:spawnProc "$@:3:$#"。不可否认,这是由于 BASH 的根源。它既优雅又简单。 我可以要求播放这个东西吗? @StevenLu 我已经修改了答案,以便为您提供解释。我希望它有所帮助。 太完美了!

以上是关于从 shell 脚本 (bash) 的参数列表中删除最后一个参数的主要内容,如果未能解决你的问题,请参考以下文章

shell脚本7---图形化shell

完了,良许直播中删库了……

Python:子进程并运行带有多个参数的bash脚本

Shell,Bash脚本默认参数

shell脚本--shift参数左移

sh 检查Bash shell脚本中是否存在输入参数