Bash基本习题
(1)找到本地的一个代码目录,统计里面.cpp文件(或者.java .py等等)的个数。
$ find . -name '*.cpp' | wc -l
(2)用下面的命令在/tmp目录生成一个脚本文件1.sh
- printf ‘#!/bin/bash\ngrep “processor|model name” /proc/cpuinfo\n’ > /tmp/1.sh
- 如果尝试执行这个脚本: /tmp/1.sh会出错。请修改文件属性,让脚本可以执行,给出执行结果。
chmod +x 1.sh 添加execute权限。执行结果为(服务器的CPU信息,因人而异):
processor : 0
model name : Intel(R) Xeon(R) Gold 6136 CPU @ 3.00GHz
processor : 1
model name : Intel(R) Xeon(R) Gold 6136 CPU @ 3.00GHz
processor : 2
model name : Intel(R) Xeon(R) Gold 6136 CPU @ 3.00GHz
processor : 3
model name : Intel(R) Xeon(R) Gold 6136 CPU @ 3.00GHz
(3)用下面的命令在/tmp目录中生成目录和文件
- $ mkdir -p /tmp/bash/data && touch /tmp/bash/data/foo.txt
- 建立一个目录/tmp/bash/bakup,并把文件/tmp/bash/data/foo.txt拷贝到/tmp/bash/bakup/foo_bakup.txt
- 把文件/tmp/bash/bakup/foo_bakup.txt改名为/tmp/bash/bakup/foo_bakup_YYYYMMDD.txt 其中YYYYMMDD是当天日期:年/月/日
-
$ mkdir -p /tmp/bash/data && touch /tmp/bash/data/foo.txt
-
$ mkdir /tmp/bash/bakup
-
$ cp /tmp/bash/data/foo.txt /tmp/bash/bakup/foo_bakup.txt
-
$ mv /tmp/bash/bakup/foo_bakup.txt /tmp/bash/bakup/foo_bakup_20210826.txt
(4)用下面的命令在/tmp目录中生成文件1.txt和2.txt
- seq 1 100 > /tmp/1.txt; seq 2 101 > /tmp/2.txt
- 查看两个文件各多少行。
- 查看每个文件的前5行和最后5行。
- 比较两个文件的差异。
-
$ wc -l 1.txt && wc -l 2.txt
-
$ head -n 5 1.txt && tail -n 5 1.txt && head -n 5 2.txt && tail -n 5 2.txt
-
$ diff -u 1.txt 2.txt
(5)统计根目录下的文件日期。用ls -l /会得到根目录下的文件和目录信息。其中有文件的修改日期。请用cut / awk / sort / uniq中的一个或几个,统计一下这些日期出现的频率。输出和下面类似的结果:
1 Apr 10
2 Apr 24
10 Apr 28
2 Apr 4
1 Aug 3
1 Dec 13
3 Dec 9
2 Mar 16
1 Mar 20
2 Mar 22
$ ls -l | awk '{ print $7" "$8 }' | sort | uniq -c
- 本例中awk的用法:
$x
表示第 $x$ 个参数,ls -l
打印出来的信息中第7、8两项是文件创建的月份、日期,因此我们需要这两个信息。- 本例中uniq -c的用法:去重后统计包含本行在内的出现次数。
(6)用uname -a可以看到操作系统的一些信息,用空格分割。使用sed或其他工具,把每一个信息单词分行打印出来,输出和下面类似的结果:
- Linux
- redwood
- 4.4.0-75-generic
- #96~14.04.1-Ubuntu
- SMP
- Thu
- Apr
- …
$ uname -a | sed 's# #\n#g'
本例中sed的用法:
#_
表示替换所有的_
(这里_
指代空格),#\n
表示替换为换行符号,#g
表示全部替换。
(7)hostname
- 假设hostname被赋值给变量h: h=$(hostname)
-
把hostname在屏幕上显示出来,输出如下:
-
The host name is <hostname>
#!/bin/bash
h=$(hostname)
echo "The host name is $h"
(8)&&和||
- 命令test $(( RANDOM )) -ge 30000的输出是随机的,有时候是0,有时候是1。
- 请用&&的方法,当结果是0的时候,输出”I got a large number”
- 请用||的方法,当结果是1的时候,输出”I got a small number”
-
$ test ! $(( RANDOM )) -ge 30000 && echo "I got a large number"
&&是逻辑与,只有前一项为真才会执行后一项,因此我们需要对
test $(( RANDOM )) -ge 30000
取反,即test !
。 -
$ test ! $(( RANDOM )) -ge 30000 || echo "I got a small number"
||是逻辑或,只有前一项为假才会执行后一项。
(9)保存find结果
- 用find命令时,如果遇到没有查看权限的目录或文件,find会输出到standard error。
- 将命令find /etc的standard out保存到/tmp/find.stdout,将standard error保存到/tmp/find.stderr。统计这两个文件的行数。
$ find /etc -name "*" 1> /tmp/find.stdout 2> /tmp/find.stderr
1>
表示标准输出。2>
表示错误输出。
(10)内置变量
- 在一个Bash脚本里,Bash有两个内置变量表示所有的命令行参数:
$*
和$@
。如果加上引号,有四种写法:$*, "$*", $@ 和 "$@"
。 - 对每一种写法,观察两个输出方式:(1)直接输出,比如
echo $*
(2)作为循环变量输出,比如for x in \$\* ;do echo "[$x]"; done
- 记录下每种输出的差别。
- 提示:提供命令行参数时,可以尝试做一些变换,比如加入一些带空格的参数,
print-variables.sh 1 "2 3" 4
- 参考文档,看结论是否一致。
*样例采用 1 "2 3" 4
。
echo $*
的结果为:1 2 3 4
,循环变量时为:[1]\n[2]\n[3]\n[4]
(\n
表示换行)。echo "$*"
的结果为1 2 3 4
,循环变量时为:[1 2 3 4]
。echo $@
的结果为:1 2 3 4
,循环变量时为:[1]\n[2]\n[3]\n[4]
(\n
表示换行)。echo "$@"
的结果为:1 2 3 4
,循环变量时为:[1]\n[2 3]\n[4]
(\n
表示换行)。
$*
和$@
都是传递给脚本或函数的所有参数。不同之处在于当被双引号(””)包含时,$*
会把参数看作一个整体,而$@
不会。
(11)写一个脚本,命令行参数是1-2个文件名。功能如下:
- 如果没有命令行参数,或者命令行参数大于2个,输出使用格式
- 如果只有一个参数:(1)文件不存在,提示错误(2)文件存在,则输出文件内容
- 如果有两个参数:(1)如果任何一个文件不存在,提示错误(2)如果两个文件都存在,用diff比较结果
#!bin/bash
argc=$#
echo $argc
if [ $argc -eq 1 ]
then
if [ -f $1 ]
then
cat $1
else
echo "$1 doesn't exist."
fi
elif [ $argc -eq 2 ]
then
if [ -f $1 ] && [ -f $2 ]
then
diff -u $1 $2
else
echo "$1 or $2 doesn't exist."
fi
else
echo "bash filename.sh arg1 arg2"
fi
$#
可以用来获取参数的数量。$x
可以用来获取第 $x$ 个参数。
(12)写一个函数lucky_number(),输出是一个1-100的随机整数。调用这个函数20次,输出20个结果。格式如下:
- The lucky number is 12.
- The lucky number is 37.
- …
- 提示:$(( RANDOM ))会输出一个随机数
#!/bin/bash
lucky_number() {
x=$((RANDOM))
echo "The lucky number is $((x % 100 + 1))"
}
for ((i = 1; i < 20; i++))
do
lucky_number
done
(13)打印从1-100的素数,每个一行。
#!/bin/bash
vis=(0)
for ((i=1; i<=100; i++))
do
vis[i]=0
done
for ((i=2; i<=100; i++))
do
if [ ${vis[i]} -eq 0 ]
then
echo ${i}
for ((j=i+i; j<=100; j+=i))
do
vis[j]=1
done
fi
done
shell中的数组,如果给某一个不存在的项赋值,那么这个数值就会被添加到数组的末尾。