shell 常见面试
1、求100以内的质数
#!/bin/bash n=100 for((i=1;i<=n;i++)) do for((x=1;x<=i;x++)) do b=$(( $i%$x )) if [[ $b -eq 0 ]]; then a=$a+1 fi done if [[ $a -eq 2 ]]; then echo $i " " fi a=0 done echo
执行结果
[root@auto hzb]# sh zhishu.sh 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
2、查看dockerps.log的第3行的第1列
[root@auto hzb]# [root@auto hzb]# cat dockerps.log CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b78a979df924 hub.chinacloud.com.cn/fast-pulsar.dev/pulsar-pkg-ui-all-in-one:20181123 "/entrypoint.sh nginx" 4 days ago Up 4 days 443/tcp, 0.0.0.0:19016->80/tcp pulsar-pkg-ui-all-in-one d27e04e08e94 hub.chinacloud.com.cn/fast-pulsar.dev/portal:20180926 "nginx -g 'daemon off" 3 weeks ago Up 3 weeks 443/tcp, 0.0.0.0:19012->80/tcp portal a70779e0f1a8 hub.chinacloud.com.cn/fast-wh.dev/whitehole-event:20181026 "/apps/whitehole-even" 3 weeks ago Up 3 weeks (healthy) whitehole-event "docker-entrypoint.sh" 4 months ago Up 7 weeks (healthy) mysql [root@auto hzb]# sed -n '3p' ./dockerps.log |cut -d " " -f1 d27e04e08e94
3、删除文件的最初三行
set -i '1,3d' ./dockerps.log
4、晚上11点到早上8点之前,每隔2小时,打印系统时间
[root@auto hzb]# cat date.sh #!/bin/bash echo -e "date is:\n" date
echo 1 23,1-8/2 * * * root /root/hzb/date.sh >>/etc/crontab
扩展:
crontab任务配置基本格式:
* * * * * command
分钟(0-59) 小时(0-23) 日期(1-31) 月份(1-12) 星期(0-6,0代表星期天) 命令
第1列表示分钟1~59 每分钟用*或者 */1表示
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
第6列要运行的命令
0 1 * * * /home/testuser/test.sh 每天晚上1点调用/home/testuser/test.sh */10 * * * * /home/testuser/test.sh 每10钟调用一次/home/testuser/test.sh 30 21 * * * /usr/local/etc/rc.d/lighttpd restart 上面的例子表示每晚的21:30重启apache。 45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart 上面的例子表示每月1、10、22日的4 : 45重启apache。 10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart 上面的例子表示每周六、周日的1 : 10重启apache。 0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart 上面的例子表示在每天18 : 00至23 : 00之间每隔30分钟重启apache。 0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart 上面的例子表示每星期六的11 : 00 pm重启apache。 * */1 * * * /usr/local/etc/rc.d/lighttpd restart 每一小时重启apache * 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart 晚上11点到早上7点之间,每隔一小时重启apache 0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart 每月的4号与每周一到周三的11点重启apache 0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart 一月一号的4点重启apache */30 * * * * /usr/sbin/ntpdate 210.72.145.44 每半小时同步一下时间
5、如何将本地80端口的请求转发到8080端口,当前主机IP为172.16.0.166
/sbin/iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 172.16.0.166:8080 /sbin/iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to 8080
6、获取java进程的pid
[root@auto hzb]# ps -ef|grep java|tr -s " "|cut -d " " -f2 1515 7908 22456 22749 23014
ps的输出字段间会有多个空格,所以直接用cut并不合适,用tr压缩连续空格后用cut
扩展:语法:tr [–c/d/s/t] [SET1] [SET2]
SET1: 字符集1
SET2:字符集2
-c:complement,用SET2替换SET1中没有包含的字符
-d:delete,删除SET1中所有的字符,不转换
-s: squeeze-repeats,压缩SET1中重复的字符
-t: truncate-set1,将SET1用SET2转换,一般缺省为-t
echo aaacccddd | tr -s [a-z]
acd
将语句中所有的小写字母变成大写字母,其中-t可省略
echo "Hello World I Love You" |tr -t [a-z] [A-Z] HELLO WORLD I LOVE YOU
删除指定字符
$ cat test.txt Monday 09:00 Tuesday 09:10 Wednesday 10:11
-d代表删除,[0-9]代表所有的数字,[: ]代表冒号和空格
$ cat test.txt | tr -d "[0-9][: ]" Monday Tuesday Wednesday
7、将当前目录下大于10944的文件转移到当前目录的bak下
#!/bin/bash fileinfo=($(du ./*)) length=${#fileinfo[@]} for((i=0;i<$length;i=$((i+2 )))); do if[ ${fileinfo[$i]} -le 10 ];then mv ${fileinfo[$((i+1 ))]} ./bak/ fi done
分析:du ./*的内容如下:
[root@auto test]# du ./* 0 ./bak 4 ./docker-compose.yml 4 ./header.json 8 ./test.conf 4 ./test.env 4 ./testmv.sh 289228 ./test.tar 98056 ./test.tar.gz 10944 ./test.tbz
分析:($(du ./*))
[root@auto test]# echo ${fileinfo[@]} 4 ./docker-compose.yml 4 ./header.json 8 ./test.conf 4 ./test.env 4 ./testmv.sh 289228 ./test.tar 98056 ./test.tar.gz 10944 ./test.tbz
8、linux下面的sed和awk的编写
1)如何显示文本file.txt中第二大列大于56789的行?
awk -F "," '{if($2>56789){print $0}}' file.txt
$0表示整个当前行,$1表示每行第一个字段
2)显示file.txt的1,3,5,7,10,15行?
sed -n "1p;3p;5p;7p;10p;15p" file.txt awk 'NR==1||NR==3||NR==5||…||NR=15{print $0}' file.txt
3)将file.txt的制表符,即tab,全部替换成"|"
sed-i "s#\t#\|#g" file.txt
9、请用Iptables写出只允许10.1.8.179 访问本服务器的22端口。
/sbin/iptables -A input -p tcp -dport 22 -s 10.1.8.179 -j ACCEPT /sbin/iptables -A input -p udp -dport 22 -s 10.1.8.179 -j ACCEPT /sbin/iptables -P input -j DROP
10、假设有一个脚本scan.sh,里面有1000行代码,并在vim模式下面,请按照如下要求写入对应的指令
1)将shutdown字符串全部替换成reboot :%s/shutdown/reboot/g 2)清空所有字符 :%d 3)不保存退出 q!
11、找出系统内大于50k,小于100k的文件,并删除它们。
#!/bin/bash file=`find / -size +50k -size -100k` for i in $file;do rm -rf $i done
12、脚本(如:目录dir1、dir2、dir3下分别有file1、file2、file2,请使用脚本将文件改为dir1_file1、dir2_file2、dir3_file3)
#!/bin/bash file=`ls dir[123]/file[123]` for i in $file;do mv $i ${i%/*}/${i%%/*}_${i##*/} done
${i%/*}:从右边删除最短匹配,比如dir1/file1,删除/*后,变成dir1
${i%%/*}:从右边删除最长匹配,比如dir1/file1,删除/*后,变成dir1,因为只有一个/,最短和最长匹配是一样的。
${i##*/}:从左边删除最长匹配:比如dir1/file1,删除*/后,变成file1
13、 如何计算传递进来的参数 ?
$#
14 、如何在脚本中获取脚本名称 ?
$0
15、 如何检查之前的命令是否运行成功 ?
$?
16、 如何获取文件的最后一行 ?
tail-1
17、如何获取文件的第一行 ?
head-1
18、假如文件中每行第一个元素是 FIND,如何获取第二个元素
awk'{ if ($1 == "FIND") print $2}'
19、如何进行两个整数相加 ?
A=5 B=6 echo $(($A+$B)) # 方法 2 echo $[$A+$B] # 方法 3 expr $A + $B # 方法 4 echo $A+$B | bc # 方法 5 awk 'BEGIN{print '"$A"'+'"$B"'}' # 方法 6
20、判断是否存在
if [ ! -d "/data/" ] #判断目录不存在 if [ -d "/data/" ] #判断目录存在 if [ ! -f "/data/filename" ] #判断文件不存在 if [ -f "/data/filename" ] #判断文件不存在 -e 判断对象是否存在 -d 判断对象是否存在,并且为目录 -f 判断对象是否存在,并且为常规文件 -L 判断对象是否存在,并且为符号链接 -h 判断对象是否存在,并且为软链接 -s 判断对象是否存在,并且长度不为0 -r 判断对象是否存在,并且可读 -w 判断对象是否存在,并且可写 -x 判断对象是否存在,并且可执行 -O 判断对象是否存在,并且属于当前用户 -G 判断对象是否存在,并且属于当前用户组 -nt 判断file1是否比file2新 [ "/data/file1" -nt "/data/file2" ] -ot 判断file1是否比file2旧 [ "/data/file1" -ot "/data/file2" ]
[ -z STRING ] “STRING” 的长度为零则为真。
[ -n STRING ] or [ STRING ] “STRING” 的长度为非零 non-zero则为真。
21、写出 shell 脚本中所有循环语法 ?
for:
for i in $(ls);do echo item:$i done
while:
#!/bin/bash COUNTER=0 while [ $COUNTER -lt 10 ]; do echo The counter is $COUNTER let COUNTER=COUNTER+1 done
until:
#!/bin/bash COUNTER=20 until [ $COUNTER -lt 10 ]; do echo COUNTER $COUNTER let COUNTER-=1 done
22、如何获取文本文件的第 10 行 ?
head -10 file|tail -1
23、命令:[ -z "" ] && echo 0 || echo 1
的输出是什么
0
24、name=John && echo 'My name is $name'
的输出是什么
My name is $name
25、name=John && echo “My name is $name”
的输出是什么
My name is John
26、如何只用 echo
命令获取字符串变量的一部分 ?
echo ${variable:x:y} x - 起始位置 y - 长度
例子:
variable="My name is Petras, and I am developer." echo ${variable:11:6} # 会显示 Petras
27、如果给定字符串 variable="User:123:321:/home/dir"
,如何只用 echo
命令获取 /home/dir ?
echo ${variable##*:}
28、如何使用 awk
列出 UID 小于 100 的用户 ?
awk -F: '$3<100' /etc/passwd
29、如何在 bash shell
中更改标准的域分隔符为 ":"
?
IFS=":"
30、如何打印变量的最后 5 个字符 ?
[root@auto ~]# str="aaaaaaaaaa" [root@auto ~]# echo ${str: -5} aaaaa [root@auto ~]# echo ${str:-5} aaaaaaaaaa [root@auto ~]# str="aaaabbbb" [root@auto ~]# echo ${str: +5} bbb
31、将test.txt中的内容以大写显示
[root@auto ~]# cat test.txt aaaa bbbb cccc [root@auto ~]# cat test.txt |tr a-z A-Z AAAA BBBB CCCC
32、wc的用法:
[root@auto ~]# cat test.txt aaaa bbbb ccccc [root@auto ~]# cat test.txt|wc -l 3 [root@auto ~]# cat test.txt|wc -c 16 [root@auto ~]# cat test.txt|wc -m 16 [root@auto ~]# cat test.txt|wc -w 3 [root@auto ~]# cat test.txt|wc -L 5
-c 统计字节数。
-l 统计行数。
-m 统计字符数。这个标志不能与 -c 标志一起使用。
-w 统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
-L 打印最长行的长度。
33、列出第二个字母是 e或z的文件或目录
[root@auto ~]# ls anaconda-ks.cfg hzb java0.log java1.log java1.log.lck test.txt [root@auto ~]# ls -d ?[ez]* hzb test.txt
如果是第三个字母:ls -d ??[ez]*
34、如何去除字符串中的所有空格
[root@localhost ~]# str="aa vvvvvv ccc dd" [root@localhost ~]# echo $str|tr -d " " aavvvvvvcccdd
35、写出输出数字 0 到 100 中 3 的倍数(0 3 6 9 …)的命令 ?
for i in {0..100..3}; do echo $i; done 或 for (( i=0; i<=100; i=i+3 )); do echo "Welcome $i times"; done
36、如何打印传递给脚本的所有参数 ?
echo $*
或
echo $@
37、[ $a == $b ]
和 [ $a -eq $b ]
有什么区别
[ $a == $b ] - 用于字符串比较
[ $a -eq $b ] - 用于数字比较
38、如何检查字符串是否以字母 "abc"
开头 ?
[[ $string == abc* ]]
39、[[ $string == abc* ]]
和 [[ $string == "abc*" ]]
有什么区别
[[ $string == abc* ]]
- 检查字符串是否以字母 abc 开头[[ $string == "abc*" ]]
- 检查字符串是否完全等于 abc*
40、如何列出以 ad
或 ma 开头的用户名 ?
[root@auto hzb]# egrep "^ad|^ma" /etc/passwd|cut -d: -f1 adm mail
41、$#,$*,$@,$$的用法
$# 是传给脚本的参数个数
$
0
是脚本本身的名字
$
1
是传递给该shell脚本的第一个参数
$
2
是传递给该shell脚本的第二个参数
$@ 是传给脚本的所有参数的列表
$* 是以一个单字符串显示所有向脚本传递的参数,与位置变量不同,参数可超过
9
个
$$ 是脚本运行的当前进程ID号
$? 是显示最后命令的退出状态,
0
表示没有错误,其他表示有错误
#!/bin/bash IFS=":"; echo $# echo $* echo $@ echo "$*" echo "$@" echo $$ echo $? echo $! IFS=" ";
[root@auto hzb]# ./test.sh 123 abc xyz 3 123 abc xyz 123 abc xyz 123:abc:xyz 123 abc xyz 31404 0
$* 会根据 IFS 的不同来组合值,而 $@ 则会将值用" "来组合值!
42、数组的一些操作 ?
[root@auto hzb]# arr=("xx" "aa" "yy" "bb") -定义数组 [root@auto hzb]# echo ${arr[0]} -打印第一个元素 xx [root@auto hzb]# echo ${arr[@]} -打印全部元素 xx aa yy bb [root@auto hzb]# echo ${!arr[@]} -打印每个元素的下标 0 1 2 3 [root@auto hzb]# unset arr[2] -删除第三个元素 [root@auto hzb]# echo ${arr[@]} xx aa bb [root@auto hzb]# arr[0]="BBB" -重新给第一个元素设置值 [root@auto hzb]# echo ${arr[@]} BBB aa bb