如何移植使用“$@:2”?
Posted
技术标签:
【中文标题】如何移植使用“$@:2”?【英文标题】:How to portability use "$@:2"?如何移植使用“$@:2”? 【发布时间】:2019-11-11 07:35:09 【问题描述】:在Allow for $@:2 syntax in variable assignment 上,他们说我不应该使用"$@:2"
,因为它会破坏不同的shell,我应该改用"$*:2"
。
但是使用"$*:2"
代替"$@:2"
是无稽之谈,因为使用"$@:2"
不等于"$*:2"
作为following example:
#!/bin/bash
check_args()
echo "\$#=$#"
local counter=0
for var in "$@"
do
counter=$((counter+1));
printf "$counter. '$var', ";
done
printf "\\n\\n"
# setting arguments
set -- "space1 notspace" "space2 notspace" "lastargument"; counter=1
echo $counter': ---------------- "$*"'; counter=$((counter+1))
check_args "$*"
echo $counter': ---------------- "$*:2"'; counter=$((counter+1))
check_args "$*:2"
echo $counter': ---------------- "$@:2"'; counter=$((counter+1))
check_args "$@:2"
-->
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
1: ---------------- "$*"
$#=1
1. 'space1 notspace space2 notspace lastargument',
2: ---------------- "$*:2"
$#=1
1. 'space2 notspace lastargument',
3: ---------------- "$@:2"
$#=2
1. 'space2 notspace', 2. 'lastargument',
如果我不能使用"$@:2"
(as they say),我可以用什么来代替?
这是Process all arguments except the first one (in a bash script) 的原始问题,他们将参数与空格放在一起的唯一答案是使用"$@:2"
【问题讨论】:
您需要脚本的便携性如何?如果它是特定于 bash 的,可以吗? 如果不可能,最便携的,最好的。如果它是 POSIX 可移植的就好了。 【参考方案1】:除非您点击链接,否则问题中的上下文不清楚。与the following recommendation from shellcheck.net有关:
local _help_text="$@:2"
^––SC2124 Assigning an array to a string! Assign as array, or use * instead of @ to concatenate.
简短回答:不要将事物列表(如参数)分配给普通变量,而是使用数组。
长答案:通常,"$@:2"
将获取除第一个参数之外的所有参数,每个参数都被视为一个单独的项目(“单词”)。另一方面,"$*:2"
生成一个项目,该项目由除第一个参数外的所有参数粘在一起,由空格分隔(或 $IFS
的第一个字符)。
但在您分配给普通变量的特定情况下,该变量只能存储单个项目,因此var="$@:2"
也将参数折叠为单个项目,但它的方式不如"$*:2"
。为了避免这种情况,请使用能够存储多个项目的东西:数组。所以:
var="$@:2"
稍微不那么糟糕:var="$*:2"
好多了:arrayvar=("$@:2")
(括号使它成为一个数组)
注意:要取回数组的元素,并将每个元素正确地视为单独的项目,请使用"$arrayvar[@]"
。此外,并非所有 shell 都支持数组(值得注意的是,dash
不支持它们),所以如果你使用它们,你应该确保使用 bash shebang(#!/bin/bash
或 #!/usr/bin/env bash
)。如果您真的需要移植到其他 shell,事情会变得复杂得多。
【讨论】:
【参考方案2】:$@:2
和 $*:2
都不是可移植的,许多 shell 会将两者视为无效语法而拒绝。如果你想处理除第一个参数之外的所有参数,你应该用 shift 去掉第一个参数。
first="$1"
shift
echo The arguments after the first are:
for x; do echo "$x"; done
此时,第一个参数在“$first”中,位置参数下移一个。
【讨论】:
【参考方案3】:这演示了如何将所有 $@
参数组合成一个变量,而无需破解 $@:1
或 $@:2
(live example):
#!/bin/bash
function get_all_arguments_as_single_one_unquoted()
single_argument="$(printf "%s " "$@")";
printf "unquoted arguments %s: '%s'\\n" "$#" "$single_argument";
function get_all_arguments_as_single_one_quoted()
single_argument="$1";
printf "quoted arguments %s: '%s'\\n" "$#" "$single_argument";
function escape_arguments()
escaped_arguments="$(printf '%q ' "$@")";
get_all_arguments_as_single_one_quoted "$escaped_arguments";
get_all_arguments_as_single_one_unquoted $escaped_arguments;
set -- "first argument" "last argument";
escape_arguments "$@";
-->
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
quoted arguments 1: 'first\ argument last\ argument '
unquoted arguments 4: 'first\ argument last\ argument '
正如@William Pursell 回答指出的那样,如果您只想获得@:2
参数,您可以在"$@"
之前添加shift
调用
function escape_arguments()
shift;
escaped_arguments="$(printf '%q ' "$@")";
get_all_arguments_as_single_one_quoted "$escaped_arguments";
get_all_arguments_as_single_one_unquoted $escaped_arguments;
-->
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
quoted arguments 1: 'last\ argument '
unquoted arguments 2: 'last\ argument '
【讨论】:
以上是关于如何移植使用“$@:2”?的主要内容,如果未能解决你的问题,请参考以下文章
如何将使用sysioctl.h的代码移植到MinGW gcc中?