如果 Linux Bash 脚本依赖于存在的某些文件或目录,则不能假设它们确实存在。 它需要检查它们是否确实存在。 这是怎样做到这一点的。
不要假设任何事情
当您编写脚本时,您无法对计算机上存在和不存在的内容做出假设。 如果脚本要在许多不同的计算机上分发和运行,那就更是如此。 迟早,该脚本将在不符合您的假设的计算机上运行,并且该脚本将失败或无法预测地运行。
我们在计算机上重视或创建的所有内容都存储在某种格式的文件中,所有这些文件都位于一个目录中。 脚本可以读取、写入、重命名、删除和移动文件和目录——所有你可以在命令行上做的事情。
作为人类,您拥有的优势是您可以看到目录的内容,并且知道文件是否存在,或者预期的目录是否存在。 如果脚本在操作文件时出错,可能会产生严重的破坏性后果。
Bash 提供了一套全面的测试,您可以使用它们来检测文件和目录,并测试它们的许多属性。 将这些合并到脚本中很容易,但在健壮性和精细控制方面的好处是相当可观的。
怎样在 Linux 中使用双括号条件测试
测试范围
通过将 if 语句与来自大量文件和目录测试的适当测试相结合,我们可以轻松确定文件是否存在、是否可执行或可写等等。
- -b:如果文件是块特殊文件,则返回 true。
- -C:如果文件是特殊字符,则返回 true。
- -d:如果“文件”是目录,则返回 true。
- -e: 如果文件存在则返回真。
- -F:如果文件存在并且是常规文件,则返回 true。
- -G: 如果文件有
setgid
权限集 (chmod g+
)。 - -H:如果文件是符号链接,则返回 true。
- -L:如果文件是符号链接,则返回 true。
- -k:如果设置了它的粘性位,则返回 true (
chmod +t
)。 - -p:如果文件是命名管道,则返回 true。
- -r:如果文件可读,则返回 true。
- -s:如果文件存在且不为空,则返回 true。
- -S:如果文件是套接字,则返回 true。
- -t:如果文件描述符在终端中打开,则返回 true。
- -u: 如果文件有
setuid
权限集 (chmod u+
)。 - -w:如果文件是可写的,则返回 true。
- -X:如果文件是可执行的,则返回 true。
- -O:如果 归您所有,则返回 true。
- -G:如果 归您的组所有,则返回 true。
- -N:如果文件自上次读取后已被修改,则返回 true。
- !: 逻辑非运算符。
- &&:逻辑与运算符。
- ||:逻辑或运算符。
列表以 -b
因为 -a
测试已被弃用并由 -e
测试。
怎样在 Linux 上使用 SUID、SGID 和 Sticky Bits
在脚本中使用测试
通用文件测试 if
statement 是一个简单的脚本构造。 双括号内的比较” [[ ]]
”使用 -f
测试以确定是否存在具有该名称的常规文件。
将此脚本的文本复制到编辑器中并将其保存到名为“script1.sh”的文件中,然后使用 chmod
使其可执行。
#!/bin/bash if [[ -f $1 ]] then echo "The file $1 exists." else echo "The file $1 cannot be found." fi
您必须将文件名传递给命令行上的脚本。
chmod +x script1.sh
如果您想尝试本文中的其他示例,则需要对每个脚本执行此操作。
让我们在一个简单的文本文件上尝试脚本。
./script1.sh test-file.txt
该文件存在并且脚本正确地报告了这一事实。 如果我们删除文件并重试,测试应该会失败并且脚本应该向我们报告。
./script1.sh test-file.txt
在现实生活中,您的脚本需要采取任何适当的行动。 也许它会标记错误并停止。 也许它会创建文件并继续。 它可能会从备份目录中复制一些内容以替换丢失的文件。 这完全取决于脚本的目的。 但至少现在脚本能够根据知道文件是否存在来做出决定。
这 -f
flag 测试文件是否存在,并且是“常规”文件。 换句话说,它不是看起来是文件但实际上不是的东西,例如设备文件。
我们将使用 ls 来验证“/dev/random”文件是否存在,然后查看脚本是怎样构成的。
ls -lh /dev/random
./script /dev/random
因为我们的脚本正在测试常规文件,而“/dev/random”是设备文件,所以测试失败。 很多时候,要查明文件是否存在,您需要仔细选择要使用的测试,或者需要使用多个测试。
这是“script2.sh”,用于测试常规文件和字符设备文件。
#!/bin/bash if [[ -f $1 ]] then echo "The file $1 exists." else echo "The file $1 is missing or not a regular file." fi if [[ -c $1 ]] then echo "The file $1 is a character device file." else echo "The file $1 is missing or not a special file." fi
如果我们在“/dev/random”设备文件上运行这个脚本,第一个测试会失败,而第二个测试会成功。 它将文件识别为设备文件。
./script2.sh /dev/random
实际上,它将其识别为字符设备文件。 一些设备文件是块设备文件。 就目前而言,我们的脚本无法处理这些问题。
./script2.sh /dev/sda
我们可以利用逻辑 OR
运算符并在第二个 if 语句中包含另一个测试。 这一次,无论文件是字符设备文件还是块设备文件,测试都会返回true。 这是“script3.sh”。
#!/bin/bash if [[ -f $1 ]] then echo "The file $1 exists." else echo "The file $1 is missing or not a regular file." fi if [[ -c $1 || -b $1 ]] then echo "The file $1 is a character or block device file." else echo "The file $1 is missing or not a special file." fi
此脚本识别字符设备和块设备文件。
./script3.sh /dev/random
./script3.sh /dev/sda
如果区分不同类型的设备文件对您很重要,您可以使用嵌套 if
陈述。 这是“script4.sh”。
#!/bin/bash if [[ -f $1 ]] then echo "The file $1 exists." else echo "The file $1 is missing or not a regular file." fi if [[ -c $1 ]] then echo "The file $1 is a character device file." else if [[ -b $1 ]] then echo "The file $1 is a block device file." else echo "The file $1 is missing or not a device file." fi fi
此脚本识别字符设备和块设备文件并对其进行分类。
./script4.sh /dev/random
./script4.sh /dev/sda
使用逻辑 AND 运算符,我们可以一次测试多个特征。 这是“script5.sh”。 它检查文件是否存在并且脚本对其具有读写权限。
#!/bin/bash if [[ -f $1 && -r $1 && -w $1 ]] then echo "The file $1 exists and we have read/write permissions." else echo "The file $1 is missing, not a regular file, or we can't read/write to it." fi
我们将在一个属于我们的文件上运行脚本,一个属于 root
.
./script5.sh .bashrc
./script5.sh /etc/fstab
要测试目录是否存在,请使用 -d
测试。 这是“script6.sh”。 它是备份脚本的一部分。 它做的第一件事是检查命令行传递的目录是否存在。 它使用逻辑 NOT
操作员 !
在里面 if
语句测试。
#!/bin/bash if [[ ! -d $1 ]] then echo "Creating backup directory:" $1 mkdir $1 if [[ ! $? -eq 0 ]] then echo "Couldn't create backup directory:" $1 exit fi else echo "Backup directory exists." fi # continue with file backup echo "Backing up to: "$1
如果该目录不存在,它会创建它。 如果目录创建文件,则脚本退出。 如果目录创建成功,或者目录已经存在,则脚本将继续执行其备份操作。
我们将运行脚本,然后检查 ls
和 -d
(directory) 选项备份目录是否存在。
./script6.sh Documents/project-backup
ls -d Documents/project-backup
备份目录已创建。 如果我们再次运行脚本,它应该报告该目录已经存在。
./script6.sh
该脚本找到目录并继续执行备份。
测试,不要假设
迟早,假设会导致坏事发生。 先测试,然后做出相应的反应。
知识就是力量。 使用测试为您的脚本提供所需的知识。
怎样让 Linux 脚本检测它们在虚拟机中运行