shell 脚本实战 六

摘自 shell脚本实战 第二版 第五章 用户管理

脚本35 分析磁盘用量

即便超大容量磁盘已经面世,价格也在持续下跌,但系统管理员似乎永远都得关注磁盘使用 情况,避免共享驱动器被占满。

最常见的监视技术是使用 du 命令查看目录/usr 或/home,以确定其下所有子目录的磁盘使用 情况,报告用量居于前 5 位或前 10 位的用户。但这种方法的问题在于无法统计磁盘其他位置的 使用情况。要是用户在其他磁盘中还有另外的存储空间,或是有人偷偷摸摸地把视频保存在/tmp 中的隐藏目录或者 ftp 中的未用目录,我们是无法检测到的。另外,如果主目录散布在多个磁盘, 搜索每个/home 目录未必是最佳做法。

更好的解决方案是直接从文件/etc/passwd 中获得所有的账户名,然后搜索整个文件系统,找 出每个账户所拥有的文件,如代码清单 5-1 所示。

代码 fquota

#!/bin/bash

# fquota -- 用于Unix的磁盘配额分析工具

# 假设所有用户UID都大于或等于100

MAXDISKUSAGE=20000 # 以MB为单位

for name in $(cut -d: -f1,3 /etc/passwd |awk -F: '$2 > 99 {print $1}');do
        echo -n "User $name exceeds disk quota. Disk usage is :"
        # 你需要根据个人的磁盘布局修改下面的目录列表
        # 最可能做出的改动是将/User 改为/home

        find / /usr /var /Users -xdev -user $name -type f -ls | awk '{sum+=$7}END{print sum / (1024*1024)" Mbtyes"}' # 1 -xdev 确保find 不会去遍历所有的文件系统。也就是说,它可以避免命令搜索系统区域、只读源目录、可移动设备、/proc运行进程目录(Linux 系统)等类似位置。这就是为什么要明确指定/usr、/var、/home 的原因。处于备份和管理目的,这些目录通常都会被挂载到单独的文件系统。如果它们位和根文件相同的文件系统中,那么find命令并不会因为其他命令行中被单独列出而重复搜索
done | awk "\$9 > $MAXDISKUSAGE {print \$0}" # 2 只允许磁盘用量大于预设MAXDISKUSAGE的用户发送信息

exit 0

运行结果

$ sudo ./fquota 
User nobody exceeds disk quota. Disk usage is :0 Mbtyes
User systemd-timesync exceeds disk quota. Disk usage is :0 Mbtyes
User systemd-network exceeds disk quota. Disk usage is :0 Mbtyes
User systemd-resolve exceeds disk quota. Disk usage is :0 Mbtyes
User messagebus exceeds disk quota. Disk usage is :0 Mbtyes
User syslog exceeds disk quota. Disk usage is :48.267 Mbtyes
User _apt exceeds disk quota. Disk usage is :0 Mbtyes
User tss exceeds disk quota. Disk usage is :0 Mbtyes
User uuidd exceeds disk quota. Disk usage is :0 Mbtyes
User tcpdump exceeds disk quota. Disk usage is :0 Mbtyes
User avahi-autoipd exceeds disk quota. Disk usage is :0 Mbtyes
User usbmux exceeds disk quota. Disk usage is :0 Mbtyes
User rtkit exceeds disk quota. Disk usage is :0 Mbtyes
User dnsmasq exceeds disk quota. Disk usage is :0 Mbtyes
User avahi exceeds disk quota. Disk usage is :0 Mbtyes
User cups-pk-helper exceeds disk quota. Disk usage is :0 Mbtyes
User speech-dispatcher exceeds disk quota. Disk usage is :0 Mbtyes
User kernoops exceeds disk quota. Disk usage is :0 Mbtyes
User saned exceeds disk quota. Disk usage is :0 Mbtyes
User nm-openvpn exceeds disk quota. Disk usage is :0 Mbtyes
User whoopsie exceeds disk quota. Disk usage is :0 Mbtyes
User colord exceeds disk quota. Disk usage is :0 Mbtyes
User sssd exceeds disk quota. Disk usage is :0 Mbtyes
User geoclue exceeds disk quota. Disk usage is :0 Mbtyes
User pulse exceeds disk quota. Disk usage is :0 Mbtyes
User hplip exceeds disk quota. Disk usage is :0 Mbtyes
User gnome-initial-setup exceeds disk quota. Disk usage is :0 Mbtyes
User gdm exceeds disk quota. Disk usage is :19.0689 Mbtyes
User amlogic exceeds disk quota. Disk usage is :286233 Mbtyes
User systemd-coredump exceeds disk quota. Disk usage is :193.105 Mbtyes
User sshd exceeds disk quota. Disk usage is :0 Mbtyes
User minidlna exceeds disk quota. Disk usage is :0.0175667 Mbtyes
User mysql exceeds disk quota. Disk usage is :347.761 Mbtyes
User postfix exceeds disk quota. Disk usage is :6.29425e-05 Mbtyes

精益求精

这种脚本的完整版具备某种形式的自动化电子邮件功能,可以对那些攫取磁盘空间的用户作 出警告。在下一个脚本中就展示了这种改进。

脚本36 报告磁盘占用大户

大多数系统管理员都寻求以最简单的方法解决问题,而管理磁盘配额最简单的方法就是扩 展 fquota(脚本#35),让它直接向消耗过多磁盘空间的用户发送电子邮件,以示警告,如代码清 单 5-3 所示。

代码 diskhogs

#!/bin/bash

# diskhogs -- 用于Unix的磁盘配额分析工具
# 假设所有用户的UID都大于或等于100
# 向超出配额的用户发送电子邮件并在屏幕上报告汇总信息


MAXDISKUSAGE=500

violators="/tmp/diskhogs0.$$" # 1

trap "$(which rm) -f $violators" 0 # 2

for name in $(cut -d: -f1,3 /etc/passwd |awk -F: '$2 > 99 {print $1}');do # 3
        echo -n "$name" # 4
        # 你可能需要根据个人的磁盘布局修改下面的目录列表
        # 最可能做出的改动是将/User 改为/Home

        find /usr /var /home -xdev -user $name -type f -ls | awk '{sum+=$7}END{print sum / (1024*1024) }'
done | awk "\$2 > $MAXDISKUSAGE {print \$0}" > $violators

if [ ! -s $violators ];then # 5
        echo "No users exceecd the disk quota of ${MAXDISKUSAGE}MB"
        cat $violators
        exit 0
fi


while read account usage;do
        # 6 用于发送电子邮件的管道中加入了fmt命令
        cat << EOF
"Warning: $account Exceeds Quota" $account Your disk usage is ${usage}MB, but you have been allocated only ${MAXDISKUSAGE}MB. This means that you need to delete some of your files, compress your files (see 'gzip' or 'bzip2' for powerful and easy-to-use compression programs), or talk with us about increasing your disk allocation.

Thanks for your cooperation in this matter.

Your friendly neighborhood sysadmin

EOF

echo "Account $account has $usage MB of disk space. User notified."

done < $violators

exit 0

运行结果

$ sudo ./diskhogs 
No users exceecd the disk quota of 500MB

精益求精

该脚本中一处有用的改进是允许某些用户拥有比其他用户更高的配额。这很容易做到:创建 单独的一个文件,在其中定义每个用户的磁盘配额,由脚本为没有出现在该文件中的用户设置默 认配额。包含账户名及其配额的文件可以用 grep 扫描,然后调用 cut -f2 提取第二个字段。

脚本37 提高df输出的可读性

代码 newdf

#!/bin/bash

# newdf -- 一个更友好的df版本

awkscript="/tmp/newdf.$$"

trap "rm -f $awkscript" EXIT

cat << 'EOF' > $awkscript

function showunit(size)
{ 
  mb = size / 1024;prettymb=(int(mb * 100)) / 100; # 1
  gb = mb / 1024;prettygb=(int(gb * 100)) / 100; # 2

  if (substr(size,1,1) !~ "[0-9]" ||
      substr(size,2,1) !~ "[0-9]" ) {return size}
  else if (mb < 1) { return size "K" }
  else if (gb < 1) { return prettymb "M"}
  else             { return prettygb "G"}
}
BEGIN{
  printf "%-37s %10s %7s %7s %8s %-s\n",
        "Filesystem", "size","Used","Avail","Capacity","Mounted"
}

!/Filesystem/{
        size=showunit($2);
        used=showunit($3);
        avail=showunit($4);

        printf "%-37s %10s %7s %7s %8s %-s\n",
                $1,size,used,avail,$5,$6
}
EOF

df -k|awk -f $awkscript # 3 -k 查看磁盘分区

exit 0

运行结果

$ ./newdf 
Filesystem                                  size    Used   Avail Capacity Mounted
df: /run/user/1000/doc: Operation not permitted
tmpfs                                      6.25G   2.46M   6.25G       1% /run
/dev/nvme0n1p2                          1832.28G 297.64G 1441.49G      18% /
tmpfs                                     31.26G   39.2M  31.22G       1% /dev/shm
tmpfs                                         5M       4   4.99M       1% /run/lock
tmpfs                                         4M       0      4M       0% /sys/fs/cgroup
/dev/nvme0n1p1                           510.98M   7.94M 503.04M       2% /boot/efi
overlay                                 1832.28G 297.64G 1441.49G      18% /var/lib/docker/overlay2/727cffd35dcdfd44dc5345ecfe5d5821433f37389ff6da52ac3cbaf307867543/merged
overlay                                 1832.28G 297.64G 1441.49G      18% /var/lib/docker/overlay2/6a1a0800215ebbe71cdcbb6c696b19802e6af9f0bf72e7a216d3deb206e09328/merged
overlay                                 1832.28G 297.64G 1441.49G      18% /var/lib/docker/overlay2/07ec654db7b8a78378e927587f41b42bfd0004a128069e3dd9a3a1a3056d6f55/merged
tmpfs                                      6.25G    148K   6.25G       1% /run/user/1000

精益求精

该脚本中还存在一些问题,其中最主要的是现在很多版本的 df 都包含 inode 的使用情况, 不少版本还会显示处理器内部信息,尽管这实在是没什么值得关心的(例如上面例子中的两个 map 项)。实际上,如果我们能把这些内容过滤掉,脚本会实用得多,所以,第一处改进就是给末 尾的 df 调用加上-P 选项,删除 inode 使用情况信息。(你也可以将其添加为新的一列,但这样 的话,输出会变得更宽,更难以格式化。)至于删掉那些 map 项,用 grep 就很容易搞定。只需在 后面加上|grep -v "^map"就行了。

脚本38 获取可用的磁盘空间

脚本#37 简化了 df 的输出,使其更容易阅读和理解。另一个更基本的问题,也就是系统究竟 有多少可用的磁盘空间,也可以通过 shell 脚本解决。df 命令以每个磁盘为基础报告磁盘使用情 况,但输出可能有点不太清晰:

Filesystem     512-blocks      Used Available Capacity iused      ifree %iused  Mounted on
/dev/disk1s1s1  976490576  30767272 496699848     6%  577263 2483499240    0%   /
devfs                 380       380         0   100%     658          0  100%   /dev
/dev/disk1s5    976490576        40 496699848     1%       2 2483499240    0%   /System/Volumes/VM
/dev/disk1s3    976490576   1289928 496699848     1%    2132 2483499240    0%   /System/Volumes/Preboot
/dev/disk1s6    976490576     12008 496699848     1%      19 2483499240    0%   /System/Volumes/Update
/dev/disk1s2    976490576 445264312 496699848    48% 1091811 2483499240    0%   /System/Volumes/Data
map auto_home           0         0         0   100%       0          0  100%   /System/Volumes/Data/home

更实用的 df 版本可以汇总第 4 列“Available”的值,然后以更易读的形式给出汇总结果。 用 awk 命令很容易就可以做到,如代码清单 5-9 所示。

代码diskspace

#!/bin/bash

# diskspace -- 汇总可用磁盘空间,以更合乎逻辑且易读的形式输出

tempfile="/tmp/available.$$"

trap "rm -f $tempfile" EXIT

cat << 'EOF' > $tempfile
        { sum += $4 }
    END { mb = sum / 1024
          gb = mb / 1024
          printf "%.0f MB(%.2fBG) of available disk space \n",mb ,gb
         }
EOF

df -k | awk -f $tempfile # 1 df的输出管道传给awk

exit 0

运行结果

$ ./diskspace 
5949669 MB(5810.22BG) of available disk space 

精益求精

如果你的系统在多个磁盘上拥有大量的磁盘空间,你可以扩展该脚本,使其自动返回以 TB 为单位的值。如果只是空间不足,那么看到 0.03 GB 的可用空间无疑会让人沮丧,不过这倒是一 个不错的机会去试试用脚本#36 清理磁盘空间,你说是不是?

另一个要考虑的问题是,了解所有设备上的可用磁盘空间是否更有用(包括那些不会增长的 分区,例如/boot),或者是否只报告用户卷的空间就够了。如果选择后者,那么你可以在 df 调用 后立即调用 grep,通过 grep 输出那些需要汇总的设备,或者在 grep -v 后面跟上不感兴趣的 设备名称,将其从汇总过程中排除。

脚本39 实现安全的locate

脚本#19 的 locate 尽管实用,但存在一个安全问题:如果数据库的构建进程是以 root 身份运 行,那么数据库中将包含整个系统中所有的文件和目录,这使得用户可以查看到他们本无权访问 的目录和文件名。普通用户也可以构建数据库(OS X 就是这么做的,其中的 mklocatedb 以用户 nobody 身份运行),但是这样也不妥当,因为你想要的是能够在属于自己的目录树中找到任何文 件,不管用户 nobody 能不能访问这些特定的文件和目录。

这个两难问题的一种解决方法是增加保存在 locate 数据库中的数据,使得每条记录都包含 属主、属组、权限这些附加信息。但即便如此,mklocatedb 数据库本身也不够安全,除非 locate 脚本设置 setuid 或 setgid,但考虑到系统安全,这是我们要竭力避免的。

折衷的做法是让每个用户拥有独立的.locatedb 文件。这种选择并不算太糟糕,因为只有使用 locate 命令的用户才需要个人数据库。一旦调用该命令,系统会在用户的主目录中创建.locatedb 文件,同时 cron 作业可以每晚更新.locatedb,保持同步。用户首次运行安全版的 slocate 脚本时, 脚本会输出提示信息,告知用户也许只会看到可公开访问的文件。等到第二天(取决于 cron 的 安排),用户就能得到属于自己的数据库了。

代码mkslocatedb

#!/bin/bash

# mkslocatedb -- 以用户nobody的身份构建中央公共数据库,
# 同时遍历每个用户的主目录,在其中查找.slocatedb文件。
# 如果找到,就位该用户创建爱你另外一个私有版本的locate数据库。

locatedb="/var/locate.db"
slocatedb=".slocatedb"

if [ "$(id -nu)" != "root" ] ; then
  echo "$0: Error: You must be root to run this command." >&2
  exit 1
fi

if [ "$(grep '^nobody:' /etc/passwd)" = "" ] ; then
  echo "$0: Error: you must have an account for user 'nobody'" >&2
  echo "to create the default slocate database." >&2; exit 1
fi

cd /            # 避开执行su之后的当前目录的权限问题。

# 首先,创建或更新公共数据库

# -c 变更为帐号为 USER 的使用者并执行指令(command)后再变回原来使用者
# -f 或 --fast 不必读启动档(如 csh.cshrc 等),仅用于 csh 或 tcsh
# -m -p 或 --preserve-environment 执行 su 时不改变环境变数
# 脚本中使用的su命令很有讲究,因为默认情况下,su不仅会修改有效用户ID,还会导入相应的用户环境。除非指定-m选项(该选项可以禁止带入用户环境),否则最终会在Unix系统中产生莫名其妙的错误信息。-f选项再多一层保险,绕过csh或tcsh用户的.cshrc文件
su -fm nobody -c "find / -print" > $locatedb 2>/dev/null
echo "building default slocate database (user = nobody)"
echo ... result is $(wc -l < $locatedb) lines long.

# 遍历所有用户的主目录,看看谁有.slocatedb 文件
for account in $(cut -d: -f1 /etc/passwd)
do
  homedir="$(grep "^${account}:" /etc/passwd | cut -d: -f6)"

  if [ "$homedir" = "/" ] ; then
    continue    # 如果是根目录,则不建立文件
  elif [ -e $homedir/$slocatedb ] ; then
    echo "building slocate database for user $account"
    su -m $account -c "find / -print" > $homedir/$slocatedb \
     2>/dev/null
    chmod 600 $homedir/$slocatedb
    chown $account $homedir/$slocatedb
    echo ... result is $(wc -l < $homedir/$slocatedb) lines long.
  fi
done

exit 0

代码 slocate

#!/bin/bash

# slocate -- 尝试在用户自己的安全slocatedb数据库中搜索指定的模式
# 如果找不到,则意味着数据库不安全,输出警告信息并创建数据库。
# 如果个人的.slocatedb 数据库为空,则使用系统数据库

locatedb="/var/locate.db"
slocatedb="$HOME/.slocatedb"

if [ ! -e $slocatedb -o "$1" = "--explain" ];then
        cat << "EOF" >&2
Warning: Secure locate keeps a private database for each user, and your
database hasn't yet been created. Until it is (probably late tonight),
I'll just use the public locate database, which will show you all
publicly accessible matches rather than those explicitly available to
account ${USER:-$LOGNAME}.
EOF

        if [ "$1" = "--explain" ];then
                exit 0
        fi

        # 在继续往下进行之前,先创建.slocatedb,这样下次脚本
        # mkslocatedb运行的时候,cron就可以向其中填入内容。

        touch $slocatedb        # mkslocatedb 会在下次建立该文件
        chmod 600 $slocatedb    # 设置好正确的权限

elif [ -s $slocatedb ];then # 判断文件大小是否为零
        locatedb=#slocatedb
else
        echo "Warning: using public database. Use \"$0 --explain\" for details." >&2
fi


if [ -z "$1" ];then
        echo "Usage: $0 pattern" >&2; exit 1
fi

exec grep -i "$1" $locatedb

运行结果

# 以 root 身份运行脚本 mkslocatedb
# mkslocatedb 
building default slocate database (user = nobody) 
... result is 99809 lines long.

building slocate database for user taylor 
... result is 99808 lines long.

# 先尝试以用户 tintin 的身份(该用户没有.slocatedb 文件)搜索匹配指定模式的文件:
tintin $ slocate Taylor-Self-Assess.doc 
Warning: using public database. Use "slocate --explain" for details. 
$

# 现在,再以用户 taylor 的身份输入相同的命令,taylor 是待查找文件的属主:
taylor $ slocate Taylor-Self-Assess.doc 
/Users/taylor/Documents/Merrick/Taylor-Self-Assess.doc

精益求精

如果文件系统内的文件数量众多,那么这种方法消耗的磁盘空间可不是个小数量。一种解决 方法是确保单独的.slocatedb 数据库中不包含已经出现在中央数据库中的记录。这得提前做一些 处理(对两个数据库使用 sort,然后再使用 diff;或者在搜索用户文件的时候跳过/usr 和/bin), 但好处是节省了磁盘空间。

另一种方法是建立单独的.slocatedb 文件,仅引用自上次更新后访问过的文件。如果每周运 行一次 mkslocatedb 脚本的话,效果要比每天运行更好。否则,所有用户在每周一就都回到原点 了,因为他们不太可能在周末运行 slocate 命令。

最后,还有一种简单的方法是压缩.slocatedb 文件,在使用 slocate 进行搜索的时候再将其解 压缩。脚本#33 中的 zgrep 命令可以给你一些这方面的启发。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《shell脚本实战》是一本介绍如何使用Shell编写脚本的电子书籍。Shell脚本是一种用于自动化任务和批处理的脚本语言,广泛应用于Unix、Linux和类Unix系统中。 这本电子书逐步引导读者从基础知识开始,包括Shell脚本的语法、变量、运算符、条件判断等。然后通过实例演示了如何编写各种常见的Shell脚本,例如文件操作、字符串操作、数学计算、循环、条件语句等。 《shell脚本实战》中还介绍了如何编写高级Shell脚本,例如函数、数组、正则表达式等。同时,它还展示了如何与系统命令、文件、网络、数据库等进行交互,从而帮助读者更好地掌握Shell脚本的灵活应用。 该电子书的实战部分还包括了一些实际场景下的应用示例,如日志分析、备份脚本、系统监控等。通过这些示例,读者可以学到如何解决实际问题,并将Shell脚本运用于自己的工作中。 总而言之,《shell脚本实战》是一本适合初学者和有一定基础的读者的实用电子书。通过学习本书,读者可以系统地了解Shell脚本的编写方法和应用技巧,提高工作效率,实现自动化任务,为日常工作带来便利。 ### 回答2: 《Shell脚本实战》,是一本针对Shell脚本编程的实战性电子书。本书主要面向对Shell脚本编程有一定基础的读者,旨在通过实际案例的讲解和实战练习的方式,帮助读者提升自己在Shell脚本编程方面的技能。 本书分为七个章节,分别介绍了Shell脚本编程的基础知识、字符串处理、文件操作、流程控制、函数、正则表达式以及常用工具等内容。每个章节都以案例为例,通过实际场景的描述和具体的代码示例,向读者展示了如何使用Shell脚本来解决实际问题。 书中的案例涵盖了各个领域,包括系统管理、日志分析、文本处理、数据清洗等等,读者可以通过学习这些案例来深入理解Shell脚本的应用场景和技巧。此外,书中还提供了练习题和实战项目,读者可以通过完成这些练习和项目来巩固和应用所学知识。 总的来说,《Shell脚本实战》是一本实用性很强的电子书,适合那些希望通过实践来提升Shell脚本编程能力的读者。无论是作为初学者的入门教材,还是作为有经验的开发人员的参考书,都具有一定的价值。读者可以通过阅读这本书,掌握Shell脚本编程的基础知识和技巧,提高自己的工作效率和编程水平。 ### 回答3: Shell脚本实战电子版是一本关于Shell脚本编程的实用指南。它适合编程新手和有一定编程基础的人士学习和使用。 本书首先介绍了Shell脚本的基础知识,包括Shell环境、Shell脚本的基本语法和变量、运算符、流程控制等内容。然后,书中以实际案例为例,详细介绍了如何使用Shell脚本解决各种问题。 在本书中,读者将学习如何创建和运行Shell脚本、使用Shell脚本进行文件和目录操作、处理文本文件和日志文件、在Shell脚本中使用正则表达式和通配符等技巧。此外,本书还介绍了如何使用Shell脚本编写简单的网络脚本、检测系统性能和使用Shell脚本进行系统管理等内容。 Shell脚本实战电子版内容丰富,实用性强。通过学习本书,读者可以有效地利用Shell脚本提高工作效率,解决实际问题。无论是在Linux、Unix还是Mac系统中,Shell脚本都是一种非常强大和灵活的工具,可以节省时间和精力。 总之,Shell脚本实战电子版是一本非常实用的书籍,对于希望学习和使用Shell脚本的读者来说,它是不可多得的参考资料。无论是初学者还是有一定经验的程序员,都可以从中获得实用的技巧和知识,提升自己的编程能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值