跳至内容

Bash - 数据输入和操作

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


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

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

🏁 linux, 脚本, bash, 变量

知识⭐ ⭐
复杂度⭐ ⭐

阅读时间: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 命令将参数“向左”移动了位置,并移除了前 2 个。

警告

在使用 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