bash参数列表的行为和基本结构

时间:2019-06-03 21:18:00

标签: arrays bash arguments printf

下面的示例代码演示了可以使用单行printf命令轻松检查arglist /参数,而不能使用同一命令检查根据参数创建的数组。它提醒我们,如果任何参数碰巧包含空格,则“变量”方法将失去各个参数之间的区别。

是否有一种方法可以将脚本的arglist复制到新对象,可以使用此单行printf命令对其进行检查?

脚本的参数列表在结构和行为上是否与可以在bash脚本中创建的任何对象(类似于数组,变量等)相同?

#!/bin/bash
# Only for demonstration purposes, override all arguments. 
set -- 'The dog ate the "mouse" ' but the cat?
# Create an array from script arguments.
declare -a argarray=( "$@" )
# Create a variable from script arguments.
argvariable="$@"

# Various ways of trying to inspect script arguments.
printf 'arguments:%s\n' "$@"
declare -p @
printf 'arguments, loop:\n'
countargs="0"
for x in "${@}"
do
    countargs=$(printf '%s\n' "1+$countargs" | bc)
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'

# Various ways of trying to inspect argarray.
printf 'argarray:%s\n' "$argarray"
declare -p argarray
printf 'argarray, loop:\n'
countargs="0"
for x in "${argarray[@]}"
do
    countargs=$(printf '%s\n' "1+$countargs" | bc)
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'


# Various ways of trying to inspect argvariable.
printf '\n'
printf 'argvariable:%s\n' "$argvariable"
declare -p argvariable 
printf 'argvariable in curly brackets, loop:\n'
countargs="0"
for x in "${argvariable[@]}"
do
    countargs=$(printf '%s\n' "1+$countargs" | bc)
    printf '%s\n' "$countargs: '$x'"
done

printf 'argvariable not bracketed, loop:\n'
countargs="0"
for x in $argvariable
do
    countargs=$(printf '%s\n' "1+$countargs" | bc)
    printf '%s\n' "$countargs: '$x'"
done

3 个答案:

答案 0 :(得分:1)

  

脚本的参数列表在结构和行为上是否与可以在bash脚本中创建的任何对象(类似于数组,变量等)相同?

是的,不是。存在相似之处,主要是与数组相似。让我们尝试创建一个列表并将参数与数组arr进行比较:

  • 获取参数计数:$#${#arr[@]}
  • 访问ex。第三个论点/元素:$3${arr[3]}
  • 访问第n个参数/元素:${@:$n:1}${arr[$n]}。但是数组切片也可以在数组上使用:${arr[@]:$n:1}
  • 设置第n个参数:Bu,您必须做set -- ${@:1:$((n-1))} newvalue ${@:$((n+1))}arr[$n]=newvalue
  • 右移:shift,或者set -- "${@:2}" vs arr=("${arr[@]:1}")
  • 参数始终是连续的$0 $1 $2,而您可以arr=(); arr[10]=value; arr[100]=value
  • 获取索引:$(seq $#)${!arr[@]}之比
  • 正确逃脱:"$@""${arr[@]}"
  • 作为单个字符串获取:"$*""${arr[*]}"

总结:

  • 使用$@$<number>访问脚本中的参数。
  • 您可以像在数组上一样对$@进行操作,但是您不能轻松地分配和/或删除元素。
  • 还有一个特殊的shift命令,用于转移参数。
  • “特殊参数” $@ $* $#$<number>以及shiftset命令由POSIX shell指定。 Bash阵列仅在bash上可用。

到您的脚本:

  • argvariable="$@"展开$@并使用IFS加入。因此,您将以一个字符串结尾。这等于argvariable="$*"。这样就避免了争论的逃逸。
  • countargs="0" for x in "${@}" do countargs=$(printf '%s\n' "1+$countargs" | bc) printf '%s\n' "$countargs: '$x'" done可以简化为计算ex。 print %.0s输出中的换行符:countargs=$(printf "%.0s\n" "$@" | wc -l)。另外,您可以使用一个简单的帮助功能:cntarg() { echo "$#"; }; countargs=$(cntarg "$@")。做$(printf '%s\n' "1+$countargs" | bc)是一个过大的技巧-shell支持expr命令,bash支持算术扩展$((...))。您可以countargs=$((countargs+1))甚至((countargs++))来增加变量。
  • "${argvariable[@]}"-argvariable不是数组。做"${argvariable[@]}"等于"$argvariable"
  

有没有一种方法可以将脚本的arglist复制到新对象,可以使用此一行printf命令对其进行检查?

将列表保存到数组中,就像在declare -a argarray=命令中一样。

argarray=("$@")

然后您可以像在argarray上一样在$@上进行访问和操作。

答案 1 :(得分:0)

回答“是否有一种方法可以将脚本的arglist复制到可以使用此一行printf命令检查的新对象?”

之后

set -- 'The dog ate the "mouse" ' but the cat\?

代码

argarray=( "$@" )
printf 'arguments:%s\n' "${argarray[@]}"

产生的输出与

完全相同
printf 'arguments:%s\n' "$@"

关于“脚本的参数列表在结构和行为上是否与可以在bash脚本中创建的任何对象(类似于数组,变量等)相同?”,最接近的“对象”参数列表(位置参数)是数组。数组的功能要强大得多。例如,可以单独添加,设置或删除数组元素。并且数组可以是稀疏的。参见Positional Parameters (Bash Reference Manual)Arrays (Bash Reference Manual)


请注意,可以使用以下命令打印计数的数组元素列表:

arg_idx=0
for arg in "${argarray[@]}" ; do
    printf "%d: '%s'\\n" $((++arg_idx)) "$arg"
done

答案 2 :(得分:0)

答案

  

有没有一种方法可以将脚本的arglist复制到新对象,可以使用此一行printf命令对其进行检查?

明确表示“是。请使用数组,但请正确处理。”我的示例代码中最重要的缺点是以下

printf 'argarray:%s\n' "$argarray"

,下面已更正。因此,有必要在脚本开始时例行创建argarray。然后将参数本身保留下来以供以后参考。

请注意,对于数组,检查元素本身不可用的另一种方法是declare -p argarray

由于响应而得到纠正的小缺点

  1. 用于增加countargs的“ overkill”方法
  2. 当“字符串”更清晰时,我的不精确术语“变量”
  3. 不清楚,我不仅想知道参数的总数,还想显示它们的数字索引。

在此示例代码的底部,我保留了“字符串”处理,以提醒您将参数转换为字符串是一个坏主意。

#!/bin/bash
# Only for demonstration purposes, override all arguments. 
set -- 'The dog ate the "mouse" ' but the cat?
# Create an array from script arguments.
declare -a argarray=( "$@" )
# Create a variable from script arguments.
argstring="$@"

# Various ways of trying to inspect script arguments.
printf 'arguments, printf:%s\n' "$@"
declare -p @
printf 'arguments indexed, loop:\n'
countargs="0"
for x in "${@}"
do
    countargs=$((countargs+1));
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'

# Various ways of trying to inspect argarray.
printf 'argarray, printf:%s\n' "${argarray[@]}"
declare -p argarray
printf 'argarray indexed, loop:\n'
countargs="0"
for x in "${argarray[@]}"
do
    countargs=$((countargs+1));
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'

# Various ways of trying to inspect argstring.
printf 'argstring, printf:%s\n' "$argstring"
declare -p argstring
printf 'argstring indexed, curly brackets, loop:\n'
countargs="0"
for x in "${argstring[@]}"
do
    countargs=$((countargs+1));
    printf '%s\n' "$countargs: '$x'"
done
printf 'argstring indexed, not bracketed, loop:\n'
countargs="0"
for x in $argstring
do
    countargs=$((countargs+1));
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'

结果:

> bash-example.sh
arguments, printf:The dog ate the "mouse" 
arguments, printf:but
arguments, printf:the
arguments, printf:cat?
/Users/BNW/u/kh/bin/bash-example.sh: line 11: declare: @: not found
arguments indexed, loop:
1: 'The dog ate the "mouse" '
2: 'but'
3: 'the'
4: 'cat?'

argarray, printf:The dog ate the "mouse" 
argarray, printf:but
argarray, printf:the
argarray, printf:cat?
declare -a argarray='([0]="The dog ate the \"mouse\" " [1]="but" [2]="the" [3]="cat?")'
argarray indexed, loop:
1: 'The dog ate the "mouse" '
2: 'but'
3: 'the'
4: 'cat?'

argstring, printf:The dog ate the "mouse"  but the cat?
declare -- argstring="The dog ate the \"mouse\"  but the cat?"
argstring indexed, curly brackets, loop:
1: 'The dog ate the "mouse"  but the cat?'
argstring indexed, not bracketed, loop:
1: 'The'
2: 'dog'
3: 'ate'
4: 'the'
5: '"mouse"'
6: 'but'
7: 'the'
8: 'cat?'