跳至内容

Bash - 数据输入和操作

在本章中,您将学习如何使您的脚本与用户交互并操作数据。


目标: 在本章中,您将学习如何

✔ 从用户读取输入;
✔ 操作数据条目;
✔ 在脚本中使用参数;
✔ 管理位置变量;

🏁 linux, script, bash, variable

知识: ⭐ ⭐
复杂性: ⭐ ⭐

阅读时间: 10 分钟


根据脚本的目的,它可能需要在启动时或执行期间的信息。这些信息,在脚本编写期间未预先确定,可以来自文件、用户输入,或者在输入脚本命令时作为参数传递,类似于许多 Linux 命令。

read 命令

read 命令允许您输入一个字符字符串并将其存储在一个变量中。

read 命令的语法

read [-n X] [-p] [-s] [variable]

下面的第一个示例提示您输入两个变量输入:"name" 和 "firstname",但由于没有提示,您必须提前知道情况就是这样。在这种特定输入的情况下,每个变量输入将用空格隔开。第二个示例提示输入变量 "name",并包含提示文本

read name firstname
read -p "Please type your name: " name
选项功能
-p显示提示消息。
-n限制输入的字符数。
-s隐藏输入。

当使用 -n 选项时,shell 会在指定数量的字符后自动验证输入。用户不必按下 Enter 键。

read -n5 name

read 命令允许您在用户输入信息时中断脚本的执行。用户输入被分解为分配给一个或多个预定义变量的词语。词语是通过字段分隔符分隔的字符字符串。

输入的结束由按下 Enter 键确定。

输入验证后,每个词语将存储在预定义的变量中。

词语的划分由字段分隔符字符定义。此分隔符存储在系统变量 IFS (内部字段分隔符) 中。

set | grep IFS
IFS=$' \t\n'

默认情况下,IFS 包含空格、制表符和换行符。

在不指定变量的情况下使用时,此命令只是暂停脚本。当输入验证后,脚本将继续执行。

这用于在调试时暂停脚本,或提示用户按 Enter 键继续。

echo -n "Press [ENTER] to continue..."
read

cut 命令

cut 命令允许您隔离文件或流中的列。

cut 命令的语法

cut [-cx] [-dy] [-fz] file

cut 命令的用法示例

cut -d: -f1 /etc/passwd
选项观察
-c指定要选择的字符的序列号。
-d指定字段分隔符。
-f指定要选择的列的顺序号。

此命令的主要优势在于它与流的关联,例如 grep 命令和 | 管道。

  • grep 命令“垂直”工作(从文件中的所有行中隔离一行)。
  • 这两个命令的组合允许隔离文件中特定字段

示例

grep "^root:" /etc/passwd | cut -d: -f3
0

注意

使用相同字段分隔符具有单一结构的配置文件是此命令组合的理想目标。

tr 命令

tr 命令允许您转换字符串。

tr 命令的语法

tr [-csd] string1 string2
选项观察
-c第一个字符串中未指定的字符全部转换为第二个字符串中的字符。
-d删除指定的字符。
-s将指定的字符缩减为单个单元。

以下是一个使用 tr 命令的示例。如果您使用 grep 返回 root 的 passwd 文件条目,您将获得以下结果

grep root /etc/passwd

返回

root:x:0:0:root:/root:/bin/bash

现在让我们使用 tr 命令并将行中的“o”缩减

grep root /etc/passwd | tr -s "o"

返回以下结果

rot:x:0:0:rot:/rot:/bin/bash

提取文件的名称和路径

basename 命令允许您从路径中提取文件名。

dirname 命令允许您提取文件的父路径。

示例

echo $FILE=/usr/bin/passwd
basename $FILE

这将导致 "passwd"

dirname $FILE

这将导致: "/usr/bin"

脚本的参数

当用户未输入任何信息时,使用read命令输入信息的请求会中断脚本执行。

这种方法虽然非常人性化,但在脚本被安排在晚上运行时,就会有其局限性。为了克服这个问题,可以通过参数注入所需的信息。

许多 Linux 命令都遵循这一原则。

这种方法的优势在于,一旦脚本执行,它就不需要任何人工干预就能完成。

其主要缺点是,用户必须了解脚本的语法,以避免错误。

在输入脚本命令时,会填写参数。它们之间用空格隔开。

./script argument1 argument2

执行后,脚本会将输入的参数保存到预定义的变量中:位置变量

这些变量可以在脚本中像其他任何变量一样使用,只是不能被赋值。

  • 未使用的位置变量存在,但为空。
  • 位置变量的定义方式总是相同的
变量观察
$0包含输入的脚本名称。
$1$9包含第 1 到第 9 个参数的值。
${x}包含第 x 个参数的值,大于 9。
$#包含传递的参数数量。
$*$@在一个变量中包含所有传递的参数。

示例

#!/usr/bin/env bash
#
# Author : Damien dit LeDub
# Date : september 2019
# Version 1.0.0 : Display the value of the positional arguments
# From 1 to 3

# The field separator will be "," or space
# Important to see the difference in $* and $@
IFS=", "

# Display a text on the screen:
echo "The number of arguments (\$#) = $#"
echo "The name of the script  (\$0) = $0"
echo "The 1st argument        (\$1) = $1"
echo "The 2nd argument        (\$2) = $2"
echo "The 3rd argument        (\$3) = $3"
echo "All separated by IFS    (\$*) = $*"
echo "All without separation  (\$@) = $@"

这将给出

$ ./arguments.sh one two "tree four"
The number of arguments ($#) = 3
The name of the script  ($0) = ./arguments.sh
The 1st argument        ($1) = one
The 2nd argument        ($2) = two
The 3rd argument        ($3) = tree four
All separated by IFS    ($*) = one,two,tree four
All without separation  ($@) = one two tree four

警告

注意$@$*之间的区别。它存在于参数存储格式中

  • $* : 以"$1 $2 $3 ..."格式包含参数
  • $@ : 以"$1" "$2" "$3" ...格式包含参数

通过修改IFS环境变量可以看到差异。

shift 命令

shift 命令允许你移动位置变量。

让我们修改之前示例,以说明 shift 命令对位置变量的影响

#!/usr/bin/env bash
#
# Author : Damien dit LeDub
# Date : september 2019
# Version 1.0.0 : Display the value of the positional arguments
# From 1 to 3

# The field separator will be "," or space
# Important to see the difference in $* and $@
IFS=", "

# Display a text on the screen:
echo "The number of arguments (\$#) = $#"
echo "The 1st argument        (\$1) = $1"
echo "The 2nd argument        (\$2) = $2"
echo "The 3rd argument        (\$3) = $3"
echo "All separated by IFS    (\$*) = $*"
echo "All without separation  (\$@) = $@"

shift 2
echo ""
echo "-------- SHIFT 2 ----------------"
echo ""

echo "The number of arguments (\$#) = $#"
echo "The 1st argument        (\$1) = $1"
echo "The 2nd argument        (\$2) = $2"
echo "The 3rd argument        (\$3) = $3"
echo "All separated by IFS    (\$*) = $*"
echo "All without separation  (\$@) = $@"

这将给出

./arguments.sh one two "tree four"
The number of arguments ($#) = 3
The 1st argument        ($1) = one
The 2nd argument        ($2) = two
The 3rd argument        ($3) = tree four
All separated by IFS    ($*) = one,two,tree four
All without separation  ($@) = one two tree four

-------- SHIFT 2 ----------------

The number of arguments ($#) = 1
The 1st argument        ($1) = tree four
The 2nd argument        ($2) =
The 3rd argument        ($3) =
All separated by IFS    ($*) = tree four
All without separation  ($@) = tree four

如你所见,shift 命令将参数的位置“向左”移动,删除了前两个参数。

警告

使用shift 命令时,$#$* 变量会相应地修改。

set 命令

set 命令将字符串拆分为位置变量。

set 命令的语法

set [value] [$variable]

示例

$ set one two three
$ echo $1 $2 $3 $#
one two three 3
$ variable="four five six"
$ set $variable
$ echo $1 $2 $3 $#
four five six 3

现在你可以像以前一样使用位置变量。

作者:Antoine Le Morvan

贡献者:Steven Spencer,Ganna Zhyrnova