跳转到内容跳转到页面导航:上一页 [访问键 p]/下一页 [访问键 n]
适用于 openSUSE Leap 15.6

14 Bash 和 Bash 脚本 编辑源文件

摘要

如今,许多人使用带有图形用户界面 (GUI)(如 GNOME)的计算机。虽然 GUI 提供了许多功能,但在执行自动化任务时受到限制。Shell 很好地补充了 GUI,本章概述了 shell 的几个方面,在本例中是 Bash shell。

14.1 什么是Shell 编辑源文件

传统上,Linux shell 是 Bash (Bourne again Shell)。本章提及shell时,指的是 Bash。还有其他 shell 可用(ash、csh、ksh、zsh 等),每个都有不同的特性和功能。如果您需要有关其他 shell 的更多信息,请在 YaST 中搜索shell

14.1.1 Bash 配置文件 编辑源文件

shell 可以被以下列方式调用:

  1. 交互式登录 shell。  在登录到机器时使用,通过 --login 选项调用 Bash,或者通过 SSH 登录到远程机器时使用。

  2. 普通交互式 shell。  通常是在启动 xterm、konsole、gnome-terminal 或类似命令行界面 (CLI) 工具时的情况。

  3. 非交互式 shell。  在命令行中调用 shell 脚本时被调用。

每个 shell 读取不同的配置文件。下表显示了登录和非登录 shell 配置文件。

Tip
提示

Bash 根据其运行的 shell 类型以特定顺序查找其配置文件。有关更多详细信息,请参阅 Bash 手册页 (man 1 bash)。搜索标题 INVOCATION

表 14.1: 登录 shell 的 Bash 配置文件

文件

描述

/etc/profile

请勿修改此文件,否则您的修改可能会在下次更新时被销毁。

/etc/profile.local

如果您扩展了 /etc/profile,请使用此文件

/etc/profile.d/

包含特定程序的系统级配置文件

~/.profile

在此处插入登录 shell 的用户特定配置

登录 shell 还会引用 表 14.2,“非登录 shell 的 Bash 配置文件”中列出的配置文件。

表 14.2: 非登录 shell 的 Bash 配置文件

/etc/bash.bashrc

请勿修改此文件,否则您的修改可能会在下次更新时被销毁。

/etc/bash.bashrc.local

使用此文件仅插入您的 Bash 系统级修改

~/.bashrc

在此处插入用户特定配置

此外,Bash 还使用多个文件

表 14.3: Bash 的特殊文件

文件

描述

~/.bash_history

包含您键入的所有命令的列表

~/.bash_logout

退出时执行

~/.alias

用户定义的常用命令别名。有关定义别名的更多详细信息,请参阅 man 1 alias

非登录 Shell编辑源文件

有一些特殊的 shell 可以阻止用户登录系统:/bin/false/sbin/nologin。当用户尝试登录系统时,两者都会静默失败。这旨在作为系统用户的安全措施,尽管现代 Linux 操作系统有更有效的工具来控制系统访问,例如 PAM 和 AppArmor。

openSUSE Leap 上的默认设置是将 /bin/bash 分配给人类用户,将 /bin/false/sbin/nologin 分配给系统用户。nobody 用户由于历史原因使用 /bin/bash,因为它是一个具有最低权限的用户,曾经是系统用户的默认设置。然而,当多个系统用户使用 nobody 时,所获得的一点点安全性就会丧失。应该可以将它更改为 /sbin/nologin;最快的测试方法是更改它并查看它是否破坏任何服务或应用程序。

使用以下命令列出 /etc/passwd 中分配给所有用户(系统用户和人类用户)的 shell。输出根据系统上的服务和用户而异。

> sort -t: -k 7 /etc/passwd | awk -F: '{print $1"\t" $7}' | column -t
tux               /bin/bash
nobody            /bin/bash
root              /bin/bash
avahi             /bin/false
chrony            /bin/false
dhcpd             /bin/false
dnsmasq           /bin/false
ftpsecure         /bin/false
lightdm           /bin/false
mysql             /bin/false
postfix           /bin/false
rtkit             /bin/false
sshd              /bin/false
tftp              /bin/false
unbound           /bin/false
bin               /sbin/nologin
daemon            /sbin/nologin
ftp               /sbin/nologin
lp                /sbin/nologin
mail              /sbin/nologin
man               /sbin/nologin
nscd              /sbin/nologin
polkitd           /sbin/nologin
pulse             /sbin/nologin
qemu              /sbin/nologin
radvd             /sbin/nologin
rpc               /sbin/nologin
statd             /sbin/nologin
svn               /sbin/nologin
systemd-coredump  /sbin/nologin
systemd-network   /sbin/nologin
systemd-timesync  /sbin/nologin
usbmux            /sbin/nologin
vnc               /sbin/nologin
wwwrun            /sbin/nologin
messagebus        /usr/bin/false
scard             /usr/sbin/nologin

14.1.2 目录结构 编辑源文件

下表简要概述了 Linux 系统上最重要的上层目录。在以下列表中查找有关目录和重要子目录的更详细信息。

表 14.4: 标准目录树概述

目录

内容

/

根目录——目录树的起点。

/bin

基本二进制文件,例如系统管理员和普通用户都需要使用的命令。通常也包含 shell,例如 Bash。

/boot

引导加载程序的静态文件。

/dev

访问主机特定设备所需的文件。

/etc

主机特定的系统配置文件。

/home

保存系统上所有拥有账户的用户的家目录。然而,root 的家目录不在 /home 中,而在 /root 中。

/lib

基本共享库和内核模块。

/media

可移动媒体的挂载点。

/mnt

临时挂载文件系统的挂载点。

/opt

附加应用程序软件包。

/root

超级用户 root 的家目录。

/sbin

基本系统二进制文件。

/srv

系统提供的服务数据。

/tmp

临时文件。

/usr

只读数据的辅助层级。

/var

可变数据,例如日志文件。

/windows

仅当您的系统上同时安装了 Microsoft Windows* 和 Linux 时可用。包含 Windows 数据。

以下列表提供了更详细的信息,并给出了一些可在目录中找到的文件和子目录的示例

/bin

包含 root 和其他用户都可以使用的基本 shell 命令。这些命令包括 lsmkdircpmvrmrmdir/bin 还包含 Bash,即 openSUSE Leap 中的默认 shell。

/boot

包含启动所需的数据,例如引导加载程序、内核和在内核开始执行用户模式程序之前使用的其他数据。

/dev

保存表示硬件组件的设备文件。

/etc

包含控制 X Window System 等程序运行的本地配置文件。/etc/init.d 子目录包含可在引导过程中执行的 LSB init 脚本。

/home/USERNAME

保存系统上每个拥有账户的用户的私人数据。此处的文件只能由其所有者或系统管理员修改。默认情况下,您的电子邮件目录和个人桌面配置以隐藏文件和目录的形式位于此处,例如 .gconf/.config

Note
注意:网络环境中的家目录

如果您在网络环境中工作,您的家目录可能会被映射到文件系统中除 /home 之外的目录。

/lib

包含引导系统和运行根文件系统中命令所需的基本共享库。Windows 中共享库的等效项是 DLL 文件。

/media

包含可移动媒体(例如 CD-ROM、闪存盘和数码相机(如果它们使用 USB))的挂载点。/media 通常保存除系统硬盘之外的任何类型的驱动器。当您的可移动媒体插入或连接到系统并已挂载时,您可以从此处访问它。

/mnt

此目录提供了一个临时挂载文件系统的挂载点。root 可以在此处挂载文件系统。

/opt

保留用于安装第三方软件。可选软件和大型附加程序包可以在此处找到。

/root

用户 root 的家目录。root 的个人数据位于此处。

/run

一个由 systemd 和各种组件使用的 tmpfs 目录。/var/run/run 的符号链接。

/sbin

正如 s 所表示的,此目录包含超级用户的实用程序。/sbin 除了 /bin 中的二进制文件外,还包含引导、恢复和修复系统所必需的二进制文件。

/srv

保存系统提供的服务数据,例如 FTP 和 HTTP。

/tmp

此目录由需要临时存储文件的程序使用。

Important
重要提示:启动时清理 /tmp

存储在 /tmp 中的数据不保证在系统重启后仍然存在。例如,它取决于 /etc/tmpfiles.d/tmp.conf 中进行的设置。

/usr

/usr 与用户无关,而是 Unix 系统资源的首字母缩写。 /usr 中的数据是静态的、只读的数据,可以在符合 文件系统层次结构标准 (FHS) 的各种主机之间共享。此目录包含所有应用程序,包括 GNOME 等图形桌面,并在文件系统中建立一个辅助层次结构。 /usr 包含多个子目录,例如 /usr/bin/usr/sbin/usr/local/usr/share/doc

/usr/bin

包含通用可访问的程序。

/usr/sbin

包含系统管理员专用的程序,例如修复功能。

/usr/local

在此目录中,系统管理员可以安装本地的、与发行版无关的扩展。

/usr/share/doc

包含各种文档文件和您系统的发行说明。在 manual 子目录中可以找到本手册的在线版本。如果安装了多种语言,此目录可能包含不同语言的手册版本。

packages 下可以找到您系统上安装的软件包中包含的文档。对于每个软件包,都会创建一个子目录 /usr/share/doc/packages/PACKAGENAME,其中通常包含软件包的 README 文件,有时还有示例、配置文件或其他脚本。

如果您的系统上安装了 HOWTO,/usr/share/doc 还包含 howto 子目录,其中可以找到有关 Linux 软件设置和操作的许多任务的附加文档。

/var

/usr 保存静态、只读数据,而 /var 用于在系统操作期间写入的数据,因此是可变数据,例如日志文件或假脱机数据。有关 /var/log/ 下可以找到的最重要日志文件的概述,请参阅 表 21.1,“日志文件”

/windows

仅当您的系统上同时安装了 Microsoft Windows 和 Linux 时才可用。包含 Windows 分区上可用的 Windows 数据。您是否可以编辑此目录中的数据取决于您的 Windows 分区使用的文件系统。如果是 FAT32,您可以打开和编辑此目录中的文件。对于 NTFS,openSUSE Leap 还包括写入访问支持。但是,NTFS-3g 文件系统的驱动程序功能有限。

14.2 编写 shell 脚本 编辑源文件

Shell 脚本提供了一种方便的方式来执行各种任务:收集数据、在文本中搜索单词或短语以及其他有用的事情。以下示例显示了一个打印文本的小型 shell 脚本

示例 14.1: 打印文本的 shell 脚本
#!/bin/sh 1
# Output the following line: 2
echo "Hello World" 3

1

第一行以 Shebang 字符 (#!) 开头,表明此文件是一个脚本。解释器在 Shebang 之后指定,并执行该脚本。在此示例中,指定的解释器是 /bin/sh

2

第二行是注释,以井号开头。我们建议您注释掉难懂的行。通过适当的注释,您可以记住该行的目的和功能。此外,其他读者也能更好地理解您的脚本。在开发社区中,注释被认为是良好的实践。

3

第三行使用内置命令 echo 打印相应的文本。

在运行此脚本之前,需要满足一些先决条件

  1. 每个脚本都应该包含一个 Shebang 行(如上例所示)。如果缺少此行,则需要手动调用解释器。

  2. 您可以将脚本保存在任何位置。但是,最好将其保存在 shell 可以找到的目录中。shell 中的搜索路径由环境变量 PATH 确定。普通用户对 /usr/bin 没有写入权限。因此,建议将脚本保存在用户目录 ~/bin/ 中。上述示例将命名为 hello.sh

  3. 脚本需要可执行权限。使用以下命令设置权限

    > chmod +x ~/bin/hello.sh

如果您满足了上述所有先决条件,您可以通过以下方式执行脚本

  1. 作为绝对路径。  脚本可以使用绝对路径执行。在我们的例子中,它是 ~/bin/hello.sh

  2. 任何地方。  如果 PATH 环境变量包含脚本所在的目录,您可以使用 hello.sh 执行脚本。

14.3 重定向命令事件 编辑源文件

每个命令可以使用三个通道,用于输入或输出

  • 标准输出。  这是默认输出通道。每当命令打印内容时,它都使用标准输出通道。

  • 标准输入。  如果命令需要来自用户或其他命令的输入,它将使用此通道。

  • 标准错误。  命令使用此通道进行错误报告。

要重定向这些通道,有以下几种可能性

命令 > 文件

将命令的输出保存到文件中,现有文件将被删除。例如,ls 命令将其输出写入文件 listing.txt

> ls > listing.txt
命令 >> 文件

将命令的输出附加到文件中。例如,ls 命令将其输出附加到文件 listing.txt

> ls >> listing.txt
命令 < 文件

将文件作为给定命令的输入读取。例如,read 命令将文件内容读入变量中

> read a < foo
命令1 | 命令2

将左侧命令的输出重定向作为右侧命令的输入。例如,cat 命令输出 /proc/cpuinfo 文件的内容。此输出由 grep 用于仅过滤包含 cpu 的行

> cat /proc/cpuinfo | grep cpu

每个通道都有一个文件描述符:0(零)用于标准输入,1用于标准输出,2用于标准错误。允许在 <> 字符之前插入此文件描述符。例如,以下行搜索以 foo 开头的文件,但通过将其重定向到 /dev/null 来抑制其错误。

> find / -name "foo*" 2>/dev/null

14.4 使用别名 编辑源文件

别名是一个或多个命令的快捷定义。别名的语法是

alias NAME=DEFINITION

例如,以下行定义了一个别名 lt,它输出长列表(选项 -l),按修改时间排序(-t),并以反向排序顺序打印(-r)。

> alias lt='ls -ltr'

要查看所有别名定义,请使用 alias。使用 unalias 和相应的别名名称删除您的别名。

14.5 在 Bash 中使用变量 编辑源文件

Shell 变量可以是全局的或局部的。全局变量,或环境变量,可以在所有 shell 中访问。相反,局部变量仅在当前 shell 中可见。

要查看所有环境变量,请使用 printenv 命令。如果您需要知道变量的值,请将变量名称作为参数插入

> printenv PATH

变量,无论是全局的还是局部的,也可以用 echo 查看。

> echo $PATH

要设置局部变量,请使用变量名,后跟等号,再后跟值

> PROJECT="SLED"

不要在等号周围插入空格,否则会出错。要设置环境变量,请使用 export

> export NAME="tux"

要删除变量,请使用 unset

> unset NAME

下表包含您可以在 shell 脚本中使用的常用环境变量

表 14.5: 有用的环境变量

HOME

当前用户的家目录

HOST

当前主机名

LANG

当工具本地化时,它使用此环境变量中的语言。英语也可以设置为 C

PATH

shell 的搜索路径,由冒号分隔的目录列表

PS1

指定在每个命令之前打印的正常提示符

PS2

指定在执行多行命令时打印的辅助提示符

PWD

当前工作目录

USER

当前用户

14.5.1 使用参数变量 编辑源文件

例如,如果您有脚本 foo.sh,您可以这样执行它

> foo.sh "Tux Penguin" 2000

要访问传递给脚本的所有参数,您需要位置参数。这些参数包括 $1 用于第一个参数,$2 用于第二个参数,依此类推。您最多可以有九个参数。要获取脚本名称,请使用 $0

以下脚本 foo.sh 打印从 1 到 4 的所有参数

#!/bin/sh
echo \"$1\" \"$2\" \"$3\" \"$4\"

如果使用上述参数执行此脚本,您将得到

"Tux Penguin" "2000" "" ""

14.5.2 使用变量替换 编辑源文件

变量替换将模式应用于变量内容的左侧或右侧。以下列表包含可能的语法形式

${VAR#pattern}

从左侧删除最短的匹配项

> file=/home/tux/book/book.tar.bz2
> echo ${file#*/}
home/tux/book/book.tar.bz2
${VAR##pattern}

从左侧删除最长的匹配项

> file=/home/tux/book/book.tar.bz2
> echo ${file##*/}
book.tar.bz2
${VAR%pattern}

从右侧删除最短的匹配项

> file=/home/tux/book/book.tar.bz2
> echo ${file%.*}
/home/tux/book/book.tar
${VAR%%pattern}

从右侧删除最长的匹配项

> file=/home/tux/book/book.tar.bz2
> echo ${file%%.*}
/home/tux/book/book
${VAR/pattern_1/pattern_2}

PATTERN_2 替换 VARPATTERN_1 的内容

> file=/home/tux/book/book.tar.bz2
> echo ${file/tux/wilber}
/home/wilber/book/book.tar.bz2

14.6 命令分组和组合 编辑源文件

Shell 允许您连接和分组命令以进行条件执行。每个命令都会返回一个退出代码,该代码决定其操作的成功或失败。如果为 0(零),则命令成功,其他任何值都表示特定于命令的错误。

以下列表显示了如何对命令进行分组

命令1 ; 命令2

按顺序执行命令。不检查退出代码。以下行用 cat 显示文件内容,然后用 ls 打印其文件属性,无论它们的退出代码如何。

> cat filelist.txt ; ls -l filelist.txt
命令1 && 命令2

如果左侧命令成功(逻辑与),则运行右侧命令。以下行显示文件内容并仅在前面的命令成功时打印其文件属性(与此列表中的前一个条目进行比较)

> cat filelist.txt && ls -l filelist.txt
命令1 || 命令2

当左侧命令失败时运行右侧命令(逻辑或)。以下行仅在创建 /home/tux/foo 目录失败时才在 /home/wilber/bar 中创建目录

> mkdir /home/tux/foo || mkdir /home/wilber/bar
funcname(){ ... }

创建一个 shell 函数。您可以使用位置参数来访问其参数。以下行定义函数 hello 来打印一条简短消息

> hello() { echo "Hello $1"; }

您可以这样调用此函数

> hello Tux

它会打印

Hello Tux

14.7 使用常见的流程结构 编辑源文件

为了控制脚本的流程,shell 具有 whileifforcase 结构。

14.7.1 if 控制命令 编辑源文件

if 命令用于检查表达式。例如,以下代码测试当前用户是否是 Tux

if test $USER = "tux"; then
  echo "Hello Tux."
else
  echo "You are not Tux."
fi

测试表达式可以尽可能复杂或简单。以下表达式检查文件 foo.txt 是否存在

if test -e /tmp/foo.txt ; then
  echo "Found foo.txt"
fi

测试表达式也可以用方括号缩写。

if [ -e /tmp/foo.txt ] ; then
  echo "Found foo.txt"
fi

https://bash.cyberciti.biz/guide/If..else..fi 查找更多有用的表达式。

14.7.2 使用 for 命令创建循环 编辑源文件

for 循环允许您对条目列表执行命令。例如,以下代码打印当前目录中 PNG 文件的某些信息

for i in *.png; do
 ls -l $i
done

14.8 更多信息 编辑源文件

有关 Bash 的重要信息可在手册页 man bash 中找到。有关此主题的更多信息,请参阅以下列表

打印此页面