第十二章 Shell脚本编写及常见面试题(三)

简介: 第十二章 Shell脚本编写及常见面试题(三)

12.21 FTP下载文件

#!/bin/bash
if [ $# -ne 1 ]; then
    echo "Usage: $0 filename"
fi
dir=$(dirname $1)
file=$(basename $1)
ftp -n -v << EOF   # -n 自动登录
open 192.168.1.10
user admin adminpass
binary   # 设置ftp传输模式为二进制,避免MD5值不同或.tar.gz压缩包格式错误
cd $dir
get "$file"
EOF 

12.22 输入五个100数之内的字符,统计和、最小和最大

COUNT=1
SUM=0
MIN=0
MAX=100
while [ $COUNT -le 5 ]; do
    read -p "请输入1-10个整数:" INT
    if [[ ! $INT =~ ^[0-9]+$ ]]; then
        echo "输入必须是整数!"
        exit 1
    elif [[ $INT -gt 100 ]]; then
        echo "输入必须是100以内!"
        exit 1
    fi
    SUM=$(($SUM+$INT))
    [ $MIN -lt $INT ] && MIN=$INT
    [ $MAX -gt $INT ] && MAX=$INT
    let COUNT++
done
echo "SUM: $SUM"
echo "MIN: $MIN"
echo "MAX: $MAX" 

wKioL1kuHZCQQNrOAAAloooYaNM429.png

12.23 将结果分别赋值给变量

方法1:
for i in $(echo "4 5 6"); do
   eval a$i=$i
done
echo $a4 $a5 $a6
方法2:将位置参数192.168.18.1{1,2}拆分为到每个变量
num=0
for i in $(eval echo $*);do   #eval将{1,2}分解为1 2
   let num+=1
   eval node${num}="$i"
done
echo $node1 $node2 $node3
# bash a.sh 192.168.18.1{1,2}
192.168.18.11 192.168.18.12
方法3:
arr=(4 5 6)
INDEX1=$(echo ${arr[0]})
INDEX2=$(echo ${arr[1]})
INDEX3=$(echo ${arr[2]}) 

12.24 批量修改文件名

# touch article_{1..3}.html
# ls
article_1.html  article_2.html  article_3.html
现在想把article改为bbs:
方法1:
for file in $(ls *html); do
    mv $file bbs_${file#*_}
    # mv $file $(echo $file |sed -r 's/.*(_.*)/bbs\1/')
    # mv $file $(echo $file |echo bbs_$(cut -d_ -f2) 
done
方法2:
for file in $(find . -maxdepth 1 -name "*html"); do
     mv $file bbs_${file#*_}
done
方法3:
# rename article bbs *.html 

12.25 统计当前目录中以.html结尾的文件总大小

方法1:
# find . -name "*.html" -maxdepth 1 -exec du -b {} \; |awk '{sum+=$1}END{print sum}'
方法2:
for size in $(ls -l *.html |awk '{print $5}'); do
    sum=$(($sum+$size))
done
echo $sum
递归统计:
# find . -name "*.html" -exec du -k {} \; |awk '{sum+=$1}END{print sum}' 

12.26 扫描主机端口状态


#!/bin/bash
HOST=$1
PORT="22 25 80 8080"
for PORT in $PORT; do
    if echo &>/dev/null > /dev/tcp/$HOST/$PORT; then
        echo "$PORT open"
    else
        echo "$PORT close"
    fi
done 

wKiom1kuIdyj5UkEAAAONQjBJ3c657.png

12.27 Expect实现SSH免交互执行命令

需要先安装expect工具。

expect涉及用法说明:

命令描述

set可以设置超时,也可以设置变量

timeout超时等待时间,默认10s

spawn执行一个命令

expect ""匹配输出的内容

exp_continue继续执行下面匹配

\r回车

$argc统计位置参数数量

[lindex $argv 0]位置参数

puts打印字符串,类似于echo

expect{...}输入多行记录

方法1:EOF标准输出作为expect标准输入

#!/bin/bash
USER=root
PASS=123.com
IP=192.168.1.120
expect << EOF
set timeout 30
spawn ssh $USER@$IP   
expect {
    "(yes/no)" {send "yes\r"; exp_continue}
    "password:" {send "$PASS\r"}
}
expect "$USER@*"  {send "$1\r"}
expect "$USER@*"  {send "exit\r"}
expect eof 
EOF 

方法2:

#!/bin/bash
USER=root
PASS=123.com
IP=192.168.1.120
expect -c "
    spawn ssh $USER@$IP
    expect {
        \"(yes/no)\" {send \"yes\r\"; exp_continue}
        \"password:\" {send \"$PASS\r\"; exp_continue}
        \"$USER@*\" {send \"df -h\r exit\r\"; exp_continue}
    }" 

方法3:将expect脚本独立出来

login.exp登录文件:

#!/usr/bin/expect 
set ip [lindex $argv 0]
set user [lindex $argv 1]
set passwd [lindex $argv 2]
set cmd [lindex $argv 3]
if { $argc != 4 } {
puts "Usage: expect login.exp ip user passwd"
exit 1
}
set timeout 30
spawn ssh $user@$ip
expect {
    "(yes/no)" {send "yes\r"; exp_continue}
    "password:" {send "$passwd\r"}
}
expect "$user@*"  {send "$cmd\r"}
expect "$user@*"  {send "exit\r"}
expect eof 

执行命令脚本:

#!/bin/bash
HOST_INFO=user_info
for ip in $(awk '{print $1}' $HOST_INFO)
do
    user=$(awk -v I="$ip" 'I==$1{print $2}' $HOST_INFO)
    pass=$(awk -v I="$ip" 'I==$1{print $3}' $HOST_INFO)
    expect login.exp $ip $user $pass $1
done 

SSH连接信息文件:

# cat user_info

192.168.1.120 root 123456

12.28 批量修改服务器用户密码

旧密码SSH主机信息old_info文件:

#     ip     user    passwd    port

#--------------------------------------

192.168.18.217  root    123456     22

192.168.18.218  root    123456     22

修改密码脚本:

#!/bin/bash
OLD_INFO=old_info
NEW_INFO=new_info
for IP in $(awk '/^[^#]/{print $1}' $OLD_INFO); do
    USER=$(awk -v I=$IP 'I==$1{print $2}' $OLD_INFO)
    PASS=$(awk -v I=$IP 'I==$1{print $3}' $OLD_INFO)
    PORT=$(awk -v I=$IP 'I==$1{print $4}' $OLD_INFO)
    NEW_PASS=$(mkpasswd -l 8)
    echo "$IP   $USER   $NEW_PASS   $PORT" >> $NEW_INFO
    expect -c "
    spawn ssh -p$PORT $USER@$IP
    set timeout 2
    expect {
        \"(yes/no)\" {send \"yes\r\";exp_continue}
        \"password:\" {send \"$PASS\r\";exp_continue}
        \"$USER@*\" {send \"echo \'$NEW_PASS\' |passwd --stdin $USER\r exit\r\";exp_continue}
    }"
done 

生成新密码new_info文件:

192.168.18.217  root    n8wX3mU%        22

192.168.18.218  root    c87;ZnnL        22

12.29 打印乘法口诀

方法1:
# awk 'BEGIN{for(n=0;n++<9;){for(i=0;i++<n;)printf i"x"n"="i*n" ";print ""}}'
方法2:
for ((i=1;i<=9;i++)); do
   for ((j=1;j<=i;j++)); do
     result=$(($i*$j))
     echo -n "$j*$i=$result "
   done
   echo
done 

wKioL1kuHgrQ_XPxAABhsSZCEJg877.png-wh_500x0-wm_3-wmp_4-s_1515635873.png

12.30 getopts工具完善脚本命令行参数

getopts是一个解析脚本选项参数的工具。

命令格式:getopts optstring name [arg]

初次使用你要注意这几点:

1)脚本位置参数会与optstring中的单个字母逐个匹配,如果匹配到就赋值给name,否则赋值name为问号;

2)optstring中单个字母是一个选项,如果字母后面加冒号,表示该选项后面带参数,参数值并会赋值给OPTARG变量;

3)optstring中第一个是冒号,表示屏蔽系统错误(test.sh: illegal option -- h);

4)允许把选项放一起,例如-ab

下面写一个打印文件指定行的简单例子,用于引导你思路,扩展你的脚本选项功能:

复制

#!/bin/bash
while getopts :f:n: option; do
    case $option in 
        f)
            FILE=$OPTARG
      [ ! -f $FILE ] && echo "$FILE File not exist!" && exit
            ;;
        n)
            sed -n "${OPTARG}p" $FILE
            ;;
        ?)
            echo "Usage: $0 -f <file_path> -n <line_number>"
            echo "-f, --file           specified file"
            echo "-n, --line-number    print specified line"
            exit 1
        ;;
    esac
done

wKioL1kuID3zfLJWAAAeiazGKzY694.png

思路扩展:限定脚本参数,将参数保存变量,下面调用变量继续操作。

本章写的Shell脚本例子都比较实用,在面试题中也经常出现,希望大家多动手练习,不要复制粘贴就拿来跑,这样是学不会的!

相关文章
|
关系型数据库 MySQL Shell
MySQL 备份 Shell 脚本:支持远程同步与阿里云 OSS 备份
一款自动化 MySQL 备份 Shell 脚本,支持本地存储、远程服务器同步(SSH+rsync)、阿里云 OSS 备份,并自动清理过期备份。适用于数据库管理员和开发者,帮助确保数据安全。
|
11月前
|
存储 安全 Unix
七、Linux Shell 与脚本基础
别再一遍遍地敲重复的命令了,把它们写进Shell脚本,就能一键搞定。脚本本质上就是个存着一堆命令的文本文件,但要让它“活”起来,有几个关键点:文件开头最好用#!/usr/bin/env bash来指定解释器,并用chmod +x给它执行权限。执行时也有讲究:./script.sh是在一个新“房间”(子Shell)里跑,不影响你;而source script.sh是在当前“房间”里跑,适合用来加载环境变量和配置文件。
900 9
|
11月前
|
存储 Shell Linux
八、Linux Shell 脚本:变量与字符串
Shell脚本里的变量就像一个个贴着标签的“箱子”。装东西(赋值)时,=两边千万不能有空格。用单引号''装进去的东西会原封不动,用双引号""则会让里面的$变量先“变身”再装箱。默认箱子只能在当前“房间”(Shell进程)用,想让隔壁房间(子进程)也能看到,就得给箱子盖个export的“出口”戳。此外,Shell还自带了$?(上条命令的成绩单)和$1(别人递进来的第一个包裹)等许多特殊箱子,非常有用。
965 2
|
Shell
Shell脚本循环控制:shift、continue、break、exit指令
使用这些命令可以让你的Shell脚本像有生命一样动起来。正确使用它们,你的脚本就能像一场精心编排的舞蹈剧目,既有旋律的起伏,也有节奏的跳跃,最终以一场惊艳的表演结束。每一个动作、每一个转折点,都准确、优雅地完成所需要表达的逻辑。如此,你的脚本不只是冰冷的代码,它透过终端的界面,跳着有节奏的舞蹈,走进观众——使用者的心中。
427 60
|
Shell
一个用于添加/删除定时任务的shell脚本
一个用于添加/删除定时任务的shell脚本
501 1
|
11月前
|
数据采集 监控 Shell
无需Python:Shell脚本如何成为你的自动化爬虫引擎?
Shell脚本利用curl/wget发起请求,结合文本处理工具构建轻量级爬虫,支持并行加速、定时任务、增量抓取及分布式部署。通过随机UA、异常重试等优化提升稳定性,适用于日志监控、价格追踪等场景。相比Python,具备启动快、资源占用低的优势,适合嵌入式或老旧服务器环境,复杂任务可结合Python实现混合编程。
|
Web App开发 缓存 安全
Linux一键清理系统垃圾:释放30GB空间的Shell脚本实战​
这篇博客介绍了一个实用的Linux系统盘清理脚本,主要功能包括: 安全权限检查和旧内核清理,保留当前使用内核 7天以上日志文件清理和系统日志压缩 浏览器缓存(Chrome/Firefox)、APT缓存、临时文件清理 智能清理Snap旧版本和Docker无用数据 提供磁盘空间使用前后对比和大文件查找功能 脚本采用交互式设计确保安全性,适合定期维护开发环境、服务器和个人电脑。文章详细解析了脚本的关键功能代码,并给出了使用建议。完整脚本已开源,用户可根据需求自定义调整清理策略。
1305 1
|
存储 Unix Shell
确定Shell脚本在操作系统中的具体位置方法。
这对于掌握Linux的文件系统组织结构和路径方面的理解很有帮助,是我们日常工作和学习中都可能使用到的知识。以上讲解详细清晰,应用简便,是每一个想要精通操作系统的计算机爱好者必备的实用技能。
761 17
|
Linux Shell
在Linux、CentOS7中设置shell脚本开机自启动服务
以上就是在CentOS 7中设置shell脚本开机自启动服务的全部步骤。希望这个指南能帮助你更好地管理你的Linux系统。
2330 25
|
Linux Shell
Centos或Linux编写一键式Shell脚本删除用户、组指导手册
Centos或Linux编写一键式Shell脚本删除用户、组指导手册
431 4