处理除第一个参数以外的所有参数(在bash脚本中)


443

我有一个简单的脚本,其中第一个参数保留用于文件名,所有其他可选参数应传递给脚本的其他部分。

使用Google我找到了这个wiki,但是它提供了一个文字示例:

echo "${@: -1}"

我什么也无法工作,例如:

echo "${@:2}"

要么

echo "${@:2,1}"

我从终端收到“替换错误”。

这是什么问题,我如何处理传递给bash脚本的第一个参数以外的所有参数?


21
为了呼唤其他人感到困惑,提供了错误的shebang,导致"{@:2}"其无法正常工作,这就是为什么正确答案与上面相匹配的原因。
古凡特

3
您只使用了默认外壳,在Ubuntu和许多其他Linux上是破折号。在破折号中,“ $ {@:-1}”解释为:{parameter:-word}-使用默认值,如果未定义参数或为null,则使用word。因此,在破折号“ $ {@:-1}”中,结果与“ $ @”完全相同。要使用bash,只需在脚本文件中使用以下第一行:#!/ bin / bash
luart 2015年

Answers:


658

用这个:

echo "${@:2}"

语法如下:

echo "${*:2}"

也可以使用,但不建议这样做,因为正如@Gordon已经解释过的那样,使用*,它会将所有参数一起作为单个参数与空格一起运行,同时@保留它们之间的间隔(即使某些参数本身包含空格) )。与没什么区别echo,但对许多其他命令来说却很重要。


7
我只是意识到我的爆炸很糟糕:#!/usr/bin/env sh这就是为什么我遇到问题。在我删除了shebang之后,您的示例工作正常,与上面提供的效果相同
theta

110
使用"${@:2}"代替-使用*将所有参数作为一个带空格的参数一起运行,同时@保留它们之间的间隔(即使某些参数本身包含空格)。与的区别并不明显echo,但对许多其他事情来说却很重要。
戈登·戴维森

2
@GordonDavisson这里的重点是一起运行参数。如果我们传递文件名,那将是正确的。 echo足够宽恕为您串联它们;其他命令可能不太好。不要只用一种或另一种:学习之间的区别*@,以及何时使用每个。您应该平等地使用它们。何时出现问题的一个很好的例子:如果$3包含换行符(\n),则只要您具有默认$IFS变量,它将被空格替换。
Zenexer 2013年

1
@Zenexer:据我了解,问题是如何传递所有,但第一个参数“脚本的另一部分”,与echo刚刚作为例子-在这种情况下,他们应该不是一起运行。以我的经验,很少需要它们一起运行的情况(请参阅此问题为一个示例),并且"$@"几乎总是您想要的。此外,仅当$@(或$*)不在双引号中时,才会出现换行符提到的问题。
戈登·戴维森

@GordonDavisson Hmm ...你是对的,现在我想到了;换行符不应该成为问题。我一定在想别的事情。但是,我仍然不同意将它们一起运行。我需要$*在脚本中经常使用。
Zenexer

180

如果您想要一个也可以/bin/sh尝试的解决方案

first_arg="$1"
shift
echo First argument: "$first_arg"
echo Remaining arguments: "$@"

shift [n]将位置参数移动n次。A shift将的值设置$1为的值$2,将的值设置$2为的值$3,依此类推,从而将的值减小$#1。


25
+1:在将变量移走之前,您可能应该将$ 1保存到变量中。
格伦

3
出乎意料的是,foo=shift它没有达到我的期望。
Keith Smiley 2014年

我知道这已经很老了,但是请尝试foo=$(shift)
raumaan kidwai 2015年

12
@raumaankidwai不能工作有两个原因:1)shift(在shell中)没有任何输出。它只是丢弃$1并向下移动所有内容。2)$(...)启动一个子shell,它有自己的局部参数。它改变了子shell中的参数,这不会影响父对象
Ben Jackson

谢谢:)有什么方法可以somecommand "$1" "${@:2}"处理这种方法吗(即移位“内联”)?
匿名


0

遇到这个问题寻找其他东西。尽管帖子看起来相当老,但下面(至少是bash 4)显示了bash中最简单的解决方案,set -- "${@:#}"其中#是我们要保留的数组元素的起始编号:

    #!/bin/bash

    someVar="${1}"
    someOtherVar="${2}"
    set -- "${@:3}"
    input=${@}

    [[ "${input[*],,}" == *"someword"* ]] && someNewVar="trigger"

    echo -e "${someVar}\n${someOtherVar}\n${someNewVar}\n\n${@}"

基本上,set -- "${@:3}"just会像perl的shift一样弹出数组中的前两个元素,并保留所有剩余的元素,包括第三个元素。我怀疑还有一种方法可以弹出最后一个元素。

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.