《鸟哥的Linux私房菜》13章shel script习题答案

本文提供了《鸟哥的Linux私房菜》基础篇习题解答,涵盖身份及路径显示、生日倒计时计算、累加计算、文件与目录操作及解析/etc/passwd文件等任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    因为感觉对Linux命令还没有多大的感觉,所以就专门找了鸟哥的书来看一下,折腾了几天看基础篇的shell部分,收获还是蛮大的,至少对Linux命令是有点感觉了,然后往前学习的一些知识,在理论知识方面也得到了一定的扩充了。先不多说,把习题的答案分享一下。


《鸟哥的Linux私房菜》基础篇P398习题


(1)请新建一个script,当你执行该script的时候,该script可以显示你目前的身份(用whoami)和你目前所在的目录(用pwd)。

这道题的答案已经直接给出了,直接上脚本:

#!/bin/bash
# Program:
#       Showing who you are and where you are.
# History:
#       2015/07/26      XPleaf  First release
PATH=$PATH:~/bin
export PATH
echo "the user is '$(whoami)',and you are in '$(pwd)'"

执行结果:

[root@moban test]# sh sh01.sh 
the user is 'root',and you are in '/root/scripts/test'

(2)请自行写一个程序,该程序可以用来计算我还有几天可以过生日。

这道题有点纠结,题倒不是很难,但是date命令的运用要够熟悉,这里我自己采取的做法是:

  1. 用户输入类似19960621格式的生日

  2. 将用户的生日转换为当年的(比如今年是2015):20159621

  3. 将当前日期和用户生日日期(已经转化为当年)都转换为用秒来表示

  4. 距离生日秒数=用户生日日期秒数-当前日期秒数

  5. 将“距离生日秒数”转换为天数

  6. 判断该天数的正负,从而得知用户的生日过了没有

脚本如下:

#!/bin/bash
# Program:
#       Telling you how many days are there before your birthday.
# History:
#       2015/07/26      XPleaf  First release
PATH=$PATH:~/bin
export PATH

read -p "Please input your birthday like <19960621> : " bith_input

bith_input_MD=$(echo $bith_input | awk 'BEGIN {FS=""} {print $5$6$7$8}')
declare -i now_s=`date +%s`
declare -i bith_s=`date --date="$(date +%Y)$bith_input_MD" +%s`
declare -i total_s=$(($bith_s-$now_s))
declare -i total_day=$(($total_s/60/60/24))
if [ "$total_day" -gt "0" ];then
        echo "There are $total_day day(s) before your bithday."
elif [ "$total_day" -eq "0" ];then
        echo "Today is your birthday!!!~Happy Birthday to you!"
else
        echo "Your birthday in this year had gone!"
fi

执行结果:

[root@moban test]# sh sh02.sh 
Please input your birthday like <19960621> : 20150730
There are 3 day(s) before your bithday.

我感觉我这个方法是比较纠结的,所以我想肯定有很简单的方法的,知道的麻烦告诉我,非常感谢!


(3)让用户输入一个数字,程序可以由1+2+3...一直累加到用户输入的数字为止。

跟上题一样,也是交互式的,不过这题就简单多了,没有那么多的数据处理,而且在C语言中这样的题见过很多,所以是比较简单的一道题了,直接上脚本:

#!/bin/bash
# Program:
#       You input the number, and I caculate 1+2+3+...+the number.
# History:
#       2015/07/26
PATH=$PATH:~/bin
export PATH

echo "You input the number, and I caculate 1+2+3+...+the number."
read -p "Please input the number: " nu

for((i=s=0;i<=$nu;i++))
do
        s=$(($s+$i))
done

echo "1+2+3+...+$nu ==> $s"

执行结果:

[root@moban test]# sh sh03.sh 
You input the number, and I caculate 1+2+3+...+the number.
Please input the number: 100
1+2+3+...+100 ==> 5050

(4)编写一支程序,它的作用是先查看一下/root/test/logical这个名称是否存在,若不存在,则创建一个文件,使用touch来创建,创建完成后离开;如果存在的话,判断该名称是否为文件,若为文件则将之删除后新建一个目录,文件名为logical,之后离开;如果存在的话,而且该名称为目录,则删除此目录!

题目比较长,但逻辑是很简单的,简单梳理如下(这里假设/root/test目录是已经存在的):

  1. 判断/root/test目录下的logical这个名称是否存在

    (1)不存在    ==>使用touch来创建logical这个文件

    (2)存在

        a.logical是文件    ==>删除logical文件,同时创建logical目录

        b.logical是目录    ==>删除logical目录

显而易见的,用“&&”和“||”可以解决,但下面我为了表达式不写那么长,对于是否存在的判断我使用了if语句:

#!/bin/bash
# Program:
#       check the /root/test/logical
# History:
#       2015/07/26      XPleaf  First release
PATH=$PATH:~/bin
export PATH

echo "check the /root/test/logical"

test -e /root/test/logical
i=$?
if [ "$i" -eq "0" ];then
        test -f /root/test/logical && rm -rf /root/test/logical && mkdir /root/test/logical || rm -rf /root/test/logical
else
        touch /root/test/logical
fi

执行结果:

情况一:/root/test/logical不存在

[root@moban test]# ls -l /root/test/logical
ls: 无法访问/root/test/logical: 没有那个文件或目录

执行一下脚本:

[root@moban test]# sh sh04.sh 
check the /root/test/logical
[root@moban test]# ls -l /root/test/logical
-rw-r--r-- 1 root root 0 7月  26 11:05 /root/test/logical

可以看到创建了logical这个文件。


情况二:/root/test/logical存在,且为文件(即上一步的执行结果)

[root@moban test]# sh sh04.sh              
check the /root/test/logical
[root@moban test]# ls -ld /root/test/logical
drwxr-xr-x 2 root root 4096 7月  26 11:06 /root/test/logical

可以看到,此时的logical已经变成目录了,即logical文件被删除,同时创建了logical目录。


情况三:/root/test/logical存在,且为目录(即上一步的执行结果)

[root@moban test]# sh sh04.sh 
check the /root/test/logical
[root@moban test]# ls -l /root/test/logical
ls: 无法访问/root/test/logical: 没有那个文件或目录

可以看到,此时并没有/root/test/logical存在,即上一步创建的logical目录已经被删除了。


(4)我们知道/etc/passwd里面以:来分隔,第一列为账号名称。请写一个程序,可以将/etc/passwd的第一列取出,而且每一列都以一行字符串“The 1 account is "root""来显示,那个1表示行数。

直接用强大的awk就可以完成:

#!/bin/bash
# Program:
#       Remove the first list of the passwd and then output it
#       like "The count line one is : the content of the passwd.
# History:
#       2015/07/26      XPleaf  First release
PATH=$PATH:~/bain
export PATH

echo "$(awk -F ":" '{print "The " NR " account is " $1}' /etc/passwd)"

执行结果:

[root@moban test]# sh sh05.sh 
The 1 account is root
The 2 account is bin
The 3 account is daemon
The 4 account is adm
The 5 account is lp
The 6 account is sync
The 7 account is shutdown
The 8 account is halt
The 9 account is mail
The 10 account is uucp
The 11 account is operator
The 12 account is games
The 13 account is gopher
The 14 account is ftp
The 15 account is nobody
The 16 account is dbus
The 17 account is vcsa
The 18 account is abrt
The 19 account is haldaemon
The 20 account is ntp
The 21 account is saslauth
The 22 account is postfix
The 23 account is sshd
The 24 account is tcpdump
The 25 account is oldboy
The 26 account is test
The 27 account is apache
The 28 account is www
The 29 account is mysql

这道题有点坑,如果知道这道题是考awk的或者本身对awk非常熟悉的,一下子就可以想得到,但是如果前面说的两个条件都没有,那就麻烦了!刚开始我没有想到是用awk,就用了非常苦逼的方法:要出行号,就得用循环,从1开始加起;要用循环,就得知道循环结束的条件,即要知道/etc/passwd的行数;要知道行数,就得用wc······然后用cut来取第一列,再用sed来输出每一行(也是用循环)。

可惜最后瞎折腾了,理论上确实是可以实现的,我在Linux命令行上就搞了出来,但是在用vim编辑时,下面的这一行就有问题了,即sed的语法上面:

user=$(sed -n '$ip' /etc/passwd | cut -d':' -f 1)

'$ip'这里,其实我是想控制输出第几行,i是个循环的变量,但是这里却无法识别,所以最后就做不了了,还好有强大的awk,不然那就坑了啊!两种方法,那差太远了啊!

关于这个语法上面的,我也想知道为什么不行啊,知道的麻烦告诉一声了,非常感谢啊!

<think>好的,我现在需要帮助用户编写一个Linux shell脚本来列出当前系统的用户组。首先,我得确认用户的需求是什么。用户提到“查看Linux系统中用户组的情况”,所以需要明确列出哪些信息。通常,用户组的信息存储在/etc/group文件中,里面包含了组名、组密码(通常是占位符)、组ID(GID)以及属于该组的用户列表。 接下来,我应该考虑如何通过shell脚本来读取并显示这些信息。基本的思路可能是读取/etc/group文件,然后格式化输出。可能需要使用诸如cut、awk这样的命令来处理每一行数据,因为/etc/group的每一行格式是固定的,用冒号分隔不同的字段。 用户可能希望脚本以易读的方式展示信息,比如表格形式。这时候,可以使用printf来格式化输出,添加表头,然后逐行处理每个组的信息。需要注意的是,有些组可能没有用户列表,这时候可能需要显示“无”而不是空着。 另外,还要考虑脚本的可执行权限问题。用户可能需要给脚本添加执行权限,然后才能运行。所以在指导用户时,应该提醒他们使用chmod +x 脚本名来赋予权限。 还要验证脚本的正确性。比如,手动检查/etc/group中的几个组,确保脚本输出的信息准确无误。如果有错误执行的情况,比如权限不足,可能需要提示用户使用sudo或者检查文件路径是否正确。 可能还需要考虑扩展性,比如用户是否希望将输出重定向到文件,或者只显示特定类型的组。不过根据当前问题描述,用户的主要需求是列出所有用户组,所以先实现基本功能,再考虑其他选项。 最后,确保脚本的兼容性,不同的Linux发行版可能有些差异,但/etc/group的格式通常是标准的,所以这个脚本应该适用于大多数情况。同时,引用相关的参考资料,比如用户提供的引用[^2]中提到的用户管理脚本实战,可能有一些最佳实践可以借鉴。</think>以下是一个用于列出当前Linux系统用户组的Shell脚本实现步骤及代码: ### 一、实现方法 1. **查看用户组文件** Linux系统的用户组信息存储在`/etc/group`文件中,格式为: $$组名:密码占位符:GID:组成员列表$$ 2. **脚本设计逻辑** ```bash #!/bin/bash echo "当前系统用户组列表:" echo "-------------------------------------" printf "%-20s %-10s %-s\n" "组名" "GID" "组成员" awk -F: '{ members = ($4 == "") ? "无" : $4; printf "%-20s %-10s %-s\n", $1, $3, members }' /etc/group ``` ### 二、操作步骤 1. **创建脚本文件** ```bash vim list_groups.sh ``` 2. **粘贴脚本内容** ```bash #!/bin/bash echo "当前系统用户组列表:" echo "-------------------------------------" printf "%-20s %-10s %-s\n" "组名" "GID" "组成员" awk -F: '{ members = ($4 == "") ? "无" : $4; printf "%-20s %-10s %-s\n", $1, $3, members }' /etc/group ``` 3. **赋予执行权限** ```bash chmod +x list_groups.sh ``` 4. **执行脚本** ```bash ./list_groups.sh ``` ### 三、输出示例 ``` 当前系统用户组列表: ------------------------------------- 组名 GID 组成员 root 0 无 daemon 1 无 sys 3 无 adm 4 syslog ... ``` ### 四、关键点说明 1. `awk -F:` 指定冒号为字段分隔符 2. `members = ($4 == "") ? "无" : $4` 处理空组成员的情况 3. `printf` 格式化输出对齐列宽(组名20字符,GID10字符)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值