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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20398499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 08:53:40  来源:igfitidea点击:

Remove last argument from argument list of shell script (bash)

bashshellargument-passingautomator

提问by Nordanfors

This question concerns a bash script that is run in automator osx. I am using automator actions to get and filter a bunch of file references from the finder. Then I append to that list the name of the parent folder, also via an automator action. Automator then feeds these arguments to an action called "run shell script". I am not sure exactly how automator invokes the script but the argument list looks like this when echoed with: echo "$@"

这个问题涉及在 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/Online/WAV_TEST/Testbok 50/03/03000 43-003.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50

/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

In this case path to 3 files and a folder.

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

In the shell script I launch an application called ripcheckc* with the args passed from automator minus the last argument(the folder) in the list.

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

I use this to remove the last argument:

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

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

And this is echo $_args:

这是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/Online/WAV_TEST/Testbok 50/03/03000 43-003.wav

/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

Same as before but without the folder.

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

Now, if I run ripcheckc with "$@"as argument it works (but fails later on because of that last path in the argument list) If I use ${_args[@]}the application will just abort silently. When I echo $@and _argsthe output looks identical except for the last argument.

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

My question is - what is the difference between $@ and $_args that make the first valid input and the second not?

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

*The application is ripcheckc

*该应用程序是ripcheckc

I hope my question makes sense.

我希望我的问题是有道理的。

EDIT: Solved.

编辑:解决了。

采纳答案by devnull

Assuming that you already have an array, you can say:

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

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


For example, if your script contains:

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

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

invoking it with: bash scriptname foo bar bazproduces:

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

foo
bar

回答by starfry

I have used this bashone-liner before

我以前用过这个bash单线

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

It sets the argument list to the current argument list, less the last argument.

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



How it works:

这个怎么运作:

  • $#is the number of arguments
  • $((...))is an arithmetic expression, so $(($#-1))is one less than the number of arguments.
  • ${variable:position:count}is a substring expression: it extracts countcharacters from variablestarting at position. In the special casewhere variableis @, which means the argument list, it extracts countargumentsfrom the list beginning at position. Here, positionis 1for the first argument and countis one less than the number of arguments worked out previously.
  • set -- arg1...argnsets the argument listto the given arguments
  • $#是参数的数量
  • $((...))是一个算术表达式,所以$(($#-1))比参数的数量少一个。
  • ${variable:position:count}是一个子字符串表达式:它countvariable位置开始提取字符。在is的特殊情况下,这意味着参数列表,它从从 开始的列表中提取参数。这里,是第一个参数,比之前计算出的参数数量少一个。variable@countpositionposition1count
  • set -- arg1...argn将参数列表设置为给定的参数

So the end result is that the argument list is replaced with a new list, where the new list is the original list except for the last argument.

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

回答by chepner

You can also get all but the last argument with

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

"${@:0:$#}"

which, honestly, is a little sketchy, since it seems to be (ab)using the fact that arguments are numbered starting with 1, not 0.

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

Update: This only works due to a bug (fixed in 4.1.2 at the latest) in handling $@. It works in version 3.2.

更新:这仅由于处理$@. 它适用于 3.2 版。