为什么要在Shell脚本中使用声明/排版而不是X = y?

时间:2019-06-06 13:01:53

标签: bash

我最近遇到了一个使用 declare -- FOO=""显然是在非bash shell中拼写的typeset -- FOO=""

为什么我要这样做而不是普通的FOO=""export FOO

3 个答案:

答案 0 :(得分:3)

使用declare的最重要目的是控制范围,或使用其他方式无法访问的数组类型。


使用函数局部变量

举个例子:

print_dashes() { for (( i=0; i<10; i++; do printf '-'; done; echo; }

while read -p "Enter a number: " i; do
  print_dashes
  echo "You entered: $i"
done

您希望打印出用户输入的号码,对吗?但是,相反,它将始终打印i完成后留下的print_dashes的值。

请考虑:

print_dashes() {
  declare i  # ''local i'' would also have the desired effect
  for (( i=0; i<10; i++; do printf '-'; done; echo;
}

...现在i local ,因此新分配的值不会超出其调用范围。


显式声明全局变量

相反,有时您想声明一个全局变量,并让代码的读者清楚您是出于意图而做的,或者在声明为数组的同时这样做(否则declare会隐式指定全局状态。您也可以这样做:

myfunc() {
  declare arg                     # make arg local
  declare -g -A myfunc_args_seen  # make myfunc_args_seen a global associative array
  for arg; do
    myfunc_args_seen["$arg"]=1
  done

  echo "Across all invocations of myfunc, we have seen the following arguments:"
  printf ' - %q\n' "${!myfunc_args_seen[@]}"
}

声明关联数组

只能分配

Normal 外壳程序数组:my_arr=( one two three )

但是,关联数组不是这种情况,它们被键为字符串。对于这些,您需要声明它们:

declare -A my_arr=( ["one"]=1 ["two"]=2 ["three"]=3 )

答案 1 :(得分:1)

declare -i cnt=0

声明仅整数变量,该变量对于数学运算速度更快,并且始终在算术上下文中求值。

declare -l lower="$1"

声明一个变量,该变量将自动小写放入其中的任何内容,而无需任何特殊的语法访问。

declare -r unchangeable="$constant"

声明一个只读变量。

看看https://unix.stackexchange.com/questions/254367/in-bash-scripting-whats-the-different-between-declare-and-a-normal-variable进行一些有用的讨论-您可能不需要经常使用这些东西,但是如果您不知道可用的东西,那么您可能会比应该更努力地工作。

答案 2 :(得分:0)

使用 WeightRange.BordersAround(ColorIndex:=xlColorIndexAutomatic) 和/或 declare 的一个重要原因是代码划分和重用(即封装)。您可以在一个脚本中编写可由其他人获取的代码。 (注意声明/排版/只读常量/变量/函数在子shell中失去了它们的“只读性”,但是当子脚本获取其定义脚本时它们会保留它,因为源将脚本加载到当前shell中,而不是子shell中。)

由于源代码从脚本加载到当前 shell 中,因此命名空间将重叠。为了防止子脚本中的变量被其父脚本覆盖(反之亦然,取决于脚本的来源和使用的变量),您可以将变量声明为只读,这样它就不会被覆盖。

你必须小心这一点,因为一旦你声明了一些只读的东西,你就不能取消它,所以你不想声明一些可能会自然地在另一个脚本中重新定义的只读内容。例如,如果您正在编写一个具有日志功能的通用库,您可能不想在名为 typesetreadonly 或 {{1} 的函数上使用 typeset -f ,因为很可能其他脚本会使用该名称创建自己的类似日志记录功能。在这种情况下,使用定义脚本的名称作为函数、变量和/或常量名称的前缀实际上是标准做法,然后将其设为只读(例如 warnerror 等) .这会保留定义脚本中代码逻辑中使用的函数、变量和/或常量的值,这样它们就不会被源脚本覆盖和意外失败。