【问题标题】:Bash script: expansion of argument not using $@ or $*Bash 脚本:不使用 $@ 或 $* 扩展参数
【发布时间】:2015-02-02 14:52:41
【问题描述】:

使用$@,您可以对 bash 中的文件列表执行操作。示例:

script.sh:

#!/bin/bash
list=$@
for file in $list; do _commands_; done

然后我可以调用这个程序

~/path/to/./script dir1/{subdir1/*.dat,subdir2/*}

此参数将扩展为多个参数,变为$list。但现在我想要其他参数,比如 1 美元、2 美元,而这个清单是 3 美元。所以我希望dir1/{subdir1/*.dat,subdir2/*} 的扩展发生在脚本内部,而不是成为许多参数。在命令行上你可以这样做:

find dir1/{subdir1/*.dat,subdir2/*}

并获得所需的输出,即文件列表。所以我尝试了这样的事情:

arg1=$1
arg2=$2
list=$(find $3)
for file in $list; do _commands_; done
...

调用:

~/path/to/./script arg_1 arg_2 'dir1/{subdir1/*.dat,subdir2/*}'

但没有成功。非常感谢有关如何将此列表扩展为脚本内的变量的一些帮助!:)

编辑:所以下面的答案使用这些命令给出了解决方案:

arg1="$1"
arg2="$2"
shift 2

for f in "$@"; do echo "processing $f"; done;

但出于好奇,是否仍然可以将字符串dir1/{subdir1/*.dat,subdir2/*} 传递给脚本内的find 命令(或任何相同的结尾),而不使用$@,并以这种方式获取列表?这可能很有用,例如如果最好将列表作为第一个或最后一个参数,或者在某些其他情况下,即使它需要转义字符或引用参数。

【问题讨论】:

  • list=$@ 不会将$@ 复制到数组中。 list=( "$@" ) 会,但您需要将其扩展为 for file in "${list[@]}"。当您的输入变得有趣(全局字符、空格等)时,以另一种方式执行此操作会产生细微(或不那么细微)的错误。
  • 该列表将包含具有相当好名称的数据文件,因此这不应该成为问题。尽管 $list 用于调用 gnuplot 以将列出的文件绘制在一个图中。与plot for [file in '$list'] file ... 并且它现在得到的格式运行良好。
  • 现在听起来这样可以满足您的需求,那么。不过,我敦促您要小心养成习惯——我已经看到 TB 的备份被删除,因为有人认为一个目录只有好听的名称,然后缓冲区溢出创建了一个带有星号的文件,并被空格包围.

标签: linux bash shell variable-expansion brace-expansion


【解决方案1】:

您可以在脚本中包含此代码:

arg1="$1"
arg2="$2"
shift 2

for f in "$@"; do echo "processing $f"; done;

然后称它为:

~/path/to/script arg_1 arg_2 dir1/{subdir1/*.dat,subdir2/*}

使用shift 2 会将位置参数移动2 个位置,从而使$3 成为$1$4 作为$2 等。然后您可以直接调用$@ 来迭代其余的参数。

根据help shift

shift: shift [n]

  Shift positional parameters.

  Rename the positional parameters $N+1,$N+2 ... to $1,$2 ...  If N is

【讨论】:

  • 这看起来很完美,不需要转义字符或在命令行参数中引用。不熟悉 shift 命令。非常感谢!
【解决方案2】:

shell 扩展是由 shell 执行的,甚至在你的脚本被调用之前。这意味着您必须引用/转义参数。在脚本中,您可以使用eval 来执行扩展。

#!/bin/bash
arg1="$1" ; shift
arg2="$2" ; shift
eval "list=($@)"
for q in "${list[@]}" ; do echo "$q" ; done

$ ./a 123 456 'a{b,c}' 'd*'
ab ac d.pl docs

在您的示例中,我没有看到在脚本内进行扩展的意义。

#!/bin/bash
arg1="$1" ; shift
arg2="$2" ; shift
list=("$@")
for q in "${list[@]}" ; do echo "$q" ; done

或者只是

#!/bin/bash
arg1="$1" ; shift
arg2="$2" ; shift
for q in "$@" ; do echo "$q" ; done

$ ./a 123 456 a{b,c} d*
ab
ac
d.pl
docs

【讨论】:

  • 如果参数包含分号怎么办。使用 eval 解析命令行参数是危险的,你没有给出任何指示。
  • 是的,你是对的。无需在脚本内部展开。我错误地认为必须是这种情况:) 非常感谢!不过检查了第一个答案;)
  • 我没有弄错(虽然我认为我是因为轮班)。好吧,把它作为第三个参数传递给"1);ls;x=(1",看看会发生什么
  • 这不是因为它们被引用了。将"1);ls;x=(1" 作为第三个参数传递给 anubhava 的脚本,并作为第三个参数传递给你的脚本,看看区别
  • 我只想让你警告它可能会在你的回答中发生,这样某人就不会(在最坏的情况下)意外破坏他们的系统。
猜你喜欢
  • 2013-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-17
  • 1970-01-01
  • 2013-11-16
  • 1970-01-01
  • 2021-03-08
相关资源
最近更新 更多