Linux Bash :多变量赋值
1. 概述
在单行代码中分配多个变量是某些编程语言(例如 Python 和 PHP)的一个方便的功能。
在这个快速教程中,我们将仔细研究如何在 Bash 脚本中进行多变量赋值。
2. 多变量赋值
多变量赋值也称为元组解包或可迭代解包。
它允许我们在一行代码中同时分配多个变量。
让我们看一个简单的 Python 示例来了解多变量赋值的样子:
var1, var2, var3 = "I am var1", "I am var2", "I am var3"
在上面的示例中,我们一次性将三个字符串值分配给了三个变量。
接下来,让我们证明是否使用 *print()*函数将值正确分配给了变量:
print(var1)
I am var1
print(var2)
I am var2
print(var3)
I am var3
如输出所示,分配按我们预期的方式工作。
在 Bash 脚本中使用多变量分配技术可以使我们的代码看起来更紧凑,并为我们带来更好的性能,特别是当我们希望通过昂贵的命令执行的输出来分配多个变量时。
例如,假设我们要根据当前日期分配七个变量——日历周数、年、月、日、小时、分钟和秒。我们可以直接做:
WEEK="$(date +'%W')"
YEAR="$(date +'%Y')"
MONTH="$(date +'%m')"
....
这些任务运作良好。
然而,在七次date命令的执行过程中,当前时间一直在变化,我们可能会得到意想不到的结果。
此外,我们将执行七次*date命令。*如果命令是一个昂贵的过程,那么多次分配肯定会损害性能。
我们可以调整输出格式,让date命令一次性输出这些必填字段:
$ date +'%W %Y %m %d %H %M %S'
08 2021 02 23 19 15 52
换句话说,如果我们能以某种方式使用多变量赋值技术,我们只需要执行一次date命令来赋值七个变量,如下所示:
WEEK YEAR MONTH DAY HOUR MINUTE SECOND="$(date +'%W %Y %m %d %H %M %S')"
不幸的是,并非所有编程语言都支持多变量赋值功能。**Bash 和 shell 脚本不支持此功能。**因此,上面的分配将不起作用。
但是,我们可以通过其他方式实现我们的目标。
接下来,让我们弄清楚它们。
3. 使用read命令
read 命令是一个强大的Bash 内置实用程序,用于将标准输入(stdin)读取到 shell 变量。 它允许我们一次分配多个变量:
$ read -r var1 var2 var3
100 200 300 #<- We input the values here
$ echo "var1=$var1; var2=$var2; var3=$var3"
var1=100; var2=200; var3=300
我们在上面的示例中使用*-r*选项在读取值时禁用反斜杠转义。
但是,read命令从标准输入读取。在shell脚本中用作变量赋值不是那么方便。毕竟,并非所有变量都是由用户输入分配的。
但是有一些方法可以将值重定向到stdin。接下来,让我们看看如何做到这一点。
3.1. 使用进程替换和 IO 重定向
我们知道我们可以使用“ < FILE ”将FILE重定向到stdin。此外,进程替换 可以帮助我们使命令的输出看起来像一个文件。
因此,我们可以将进程替换和 IO 重定向结合在一起来提供 read命令:
read -r var1 var2 var3 < <(COMMAND)
我们用前面的date命令和七个变量的赋值问题来测试一下:
$ read -r WEEK YEAR MONTH DAY HOUR MINUTE SECOND < <(date +'%W %Y %m %d %H %M %S')
$ echo "week: $WEEK\nyear: $YEAR\nmonth: $MONTH\nday: $DAY\nhour: $HOUR\nminute: $MINUTE\nsecond: $SECOND"
week: 08
year: 2021
month: 02
day: 23
hour: 17
minute: 35
second: 17
如上面的输出所示,我们使用进程替换和 IO 重定向技巧一次性分配了七个变量。
3.2. 使用命令替换和 Here-String
或者,我们可以使用here-string 来提供read命令的stdin:
$ read -r var1 var2 var3 <<< "101 202 303"
$ echo "var1=$var1; var2=$var2; var3=$var3"
var1=101; var2=202; var3=303
如果我们用命令替换 替换硬编码字符串,我们可以使用命令的输出设置多个变量。 让我们用七个变量和date命令场景进行测试:
$ read -r WEEK YEAR MONTH DAY HOUR MINUTE SECOND <<< "$(date +'%W %Y %m %d %H %M %S')"
$ echo "week: $WEEK\nyear: $YEAR\nmonth: $MONTH\nday: $DAY\nhour: $HOUR\nminute: $MINUTE\nsecond: $SECOND"
week: 08
year: 2021
month: 02
day: 23
hour: 19
minute: 26
second: 09
我们一次性分配了七个变量。此外,date命令只执行一次。
因此,read命令可以帮助我们实现多变量赋值。
3.3. 更改分隔符
** read命令将使用 IFS 变量的值作为 *分隔 *符。**默认情况下,它是空格。
但是我们知道命令的输出并不总是由空格分隔。
让我们更改date命令的输出格式:
$ date +'%W@%F %T@%A'
08@2021-02-23 21:45:40@Tuesday
这次,输出由“@”字符分隔,并包含三个字段:周数、当前日期和时间以及当前日期的工作日。第二个字段包含一个空格。 现在,我们将一次性将三个字段分配给三个变量。 显然,它不适用于默认分隔符。我们可以通过设置IFS变量来更改分隔符:
$ IFS='@' read -r WEEK_NO DATE_TIME WEEK_DAY <<< "$(date +'%W@%F %T@%A')"
$ echo "week_no: $WEEK_NO\ndate_time: $DATE_TIME\nweek_day: $WEEK_DAY"
week_no: 08
date_time: 2021-02-23 21:53:53
week_day: Tuesday
值得一提的是,在上面的示例中,对IFS变量的更改仅影响其后的read命令。
4. 使用数组
使用命令输出分配多个变量的另一种方法是将命令输出字段分配给数组。 让我们展示它如何与date命令和七个变量示例一起使用:
$ readarray -d' ' -t ARR <<< "$(date +'%W %Y %m %d %H %M %S')"
$ echo -e "week: ${ARR[0]}\nyear: ${ARR[1]}\nmonth: ${ARR[2]}\nday: ${ARR[3]}\nhour: ${ARR[4]}\nminute: ${ARR[5]}\nsecond: ${ARR[6]}"
week: 08
year: 2021
month: 02
day: 23
hour: 22
minute: 19
second: 23
在示例中,我们使用 Bash 内置的 readarray 命令来读取date命令的输出。 ** readarray命令使用的默认分隔符是换行符**。但是我们可以使用*-d*选项将空格设置为分隔符。