清明三天假期基本都是在写脚本中度过了,今天又折腾了一个新的脚本,该脚本的作用是快速复制一个或多个命令的可执行文件和依赖库文件到一个模拟的根文件系统下的相应目录下,这个脚本平时运维估计用不到,只有自己制作一个小的Linux发行版时才有可能使用该脚本。

    脚本具体的功能如下:

    1)提示用户选择要从文本中读取要复制的命令名还是从当前终端中交互式输入命令名。

    2)用户选择前者,会自动使用vim打开一个文件,用户根据格式说明填入要复制的命令的名称,可以是多个命令,保存退出后自动执行复制操作。

   3)用户选择后者,在终端交互式的输入单个命令的名称,回车后执行复制操作。

    注意:如果目标目录没有对应的子目录则自动创建,如/bin对应的/tmp/sysroot/bin。

具体实现脚本如下(渣渣英语,百度翻译的,请见谅):

#!/bin/bash
#Program:
#      This program is used to cpoy executable file and dependency Library  
#      to the specified folder
#History:
#2016/4/4    xiaohei   v1.0
#blog:http://zww577593841.blog.51cto.com/6145493/1750689
#
LANG=zh_CN.UTF8
PATH=./:$PATH
export PATH
#要复制的命令的名字
declare cmd
#命令的可执行文件路径
declare cmdfile
#依赖库文件的路径
declare libfile
#要复制到的目标目录
declare sysroot="/tmp/sysroot"
#信号捕捉
trap 'mytrap' INT
mytrap(){
        clean_temp
        exit 1
}
#清理脚本运行过程中生成的临时文件和变量
clean_temp(){
        unset -v cmd
        unset -v cmdfile
        unset -v libfile
        unset -v sysroot
        rm -rf  ./libfile.txt
        rm -rf ./cmdlist.txt
        rm -rf ./cmdfile.txt
        rm -rf ./cmdlist.txt.bak

}
#判断是否输入一个参数,输入的参数是不是一个命令,该命令的可执行文件是否存在
analyse_cmd(){
        if [ $# -ne 1 ];then
                echo  -e "\033[31mThe parameter error\033[0m"
                return  1
        fi
        if  ! type "$1" &> /dev/null;then
                echo -e  "\033[31mnot a command\033[0m"
                return 1
        fi
        if ! which  "$1" &> /dev/null ;then
                echo -e  "\033[31mcmdfile does not exist\033[0m"
                return 1
        fi
        return 0
}
analyse_dir_file(){
        #判断要复制的文件是否存在
        if ! [ -a $1 ];then
                echo -e  "\033[31m$1  does not exist\033[0m"
                return 1
        fi
        #取文件路径名
        local  dir_file=${1%/*}
         [ -d $dir_file   ]
        #如果目录不存在则创建
        if ! [ -d $sysroot$dir_file  ];then
                mkdir -p $sysroot$dir_file
                echo -e "\033[32mcreat $sysroot$dir_file\033[0m"
                return 0
        fi
        #如果要复制到的目录已存在该文件则报错
        if  [ -a $sysroot$1 ];then
                echo -e  "\033[31m$sysroot$1 has exist\033[0m"

                return 1
        fi
        return 0
}
cp_file(){
        #调用函数分析给定的参数
        analyse_cmd $1 || return 1
        #获取命令的可执行文件的路径
        cmdfile=$(which $1)
        echo "cmdfile is:$cmdfile"
        #调用函数分析获取的路径和文件,正常则执行复制,异常则退出函数
        analyse_dir_file $cmdfile &&  cp  -a  "$cmdfile"  "$sysroot$cmdfile"   || return 1
        echo -e  "\033[32mcp $cmdfile  successful\033[0m"
        #获取命令的依赖库文件名,并保存至至文件中
        ldd $cmdfile | grep -o -E  "/[^[:space:]]+"  > ./libfile.txt
        #循环遍历文件,内容为上一条命令查找到的依赖库文件名
        while read libfile ;do
                #对库文件的绝对路径名进行分析,正常执行下一步,异常退出本次循环。
                analyse_dir_file $libfile  || continue
                #复制文件到目标路径下
                cp   "$libfile"  "$sysroot$libfile"
                echo -e "\033[32mcp $libfile successful\033[0m"
        done < ./libfile.txt
}
#手动按照固定格式在文件中添加多个命令名称
cmdlist_creat(){
        #判断文件是否存在,存在则将其改名
        if [ -f ./cmdlist.txt  ];then
                mv -f ./cmdlist.txt  ./cmdlist.txt.bak
        fi
        #给文件添加格式说明
        cat  > ./cmdlist.txt <<end
#Each line is a command 
#ls
#pwd    
end
        #编辑文件,添加要复制的命令的名字
        vim ./cmdlist.txt
}
#遍历文件,该文件保存要复制的命令的名称,复制每个命令的可执行文件和依赖库到指定的目录的相应目录中
cp_file_text(){
        #局部变量,保存命令名称
        local cmdf
        #循环遍历文件,查找没有#号开头的行的命令,调用函数执行复制操作
        while read cmdf ;do
                #排查格式说明的举例
                if [[  "$cmdf"  =~ '#'  ]];then
                        continue
                fi
                echo "$cmdf"
                cp_file $cmdf
        done < ./cmdlist.txt
}
while true ;do
cat <<end
######################################
a)Read from the text                #  
b)Read from the terminal            #
quit)quit                           #
#####################################
end
read -p "enter you choice:" option
case $option in
[aA])
        cmdlist_creat
        cp_file_text
        ;;
[bB])
        read -p "enter a cmd:"  cmd
        cp_file $cmd
        ;;
quit)
        break
        ;;
*)
        continue
        ;;
esac
done
#清理脚本生成的临时文件和变量
clean_temp

程序运行测试:

1)脚本运行效果

wKiom1cCQKuiIwokAAA0fjz-fEA319.png

2)选择从文本添加要复制的命令

wKiom1cCQQKjArQuAAAoxVW7ZDc376.png

wKioL1cCQcujKuHtAABg5Fz3t7o190.png

3)选择从终端交互式输入要添加的命令

wKiom1cCQkHDeCG8AABAWcTNIbs300.png

4)查看是否正确复制

wKioL1cCRICQJxB9AABewKVS05Y197.png

5)测试各种错误输入的报错信息,注意该脚本只能识别外部命令,bash内置命令会报错。

wKioL1cCRUOxvFsJAAA-IwvMZig407.png

wKiom1cCRRXAeUw3AAA6ol02X4o660.png

    本脚本基本是用来练习的,是为了后期自制Linux小系统准备的工具脚本。