将一些练习题以及我自己实际写过的shell脚本记录于此,供学习查询。
- 用户输入y或Y结束
while方式
#!/bin/bash
read -p "input you choice : " c
while [ "$c" != "Y" -a "$c" != "y" ]
do
read -p "input you choice : " c
done
echo "Ok!"
until方式
#!/bin/bash
until [ "$c" == "Y" -o "$c" == "y" ]
do
read -p "input your choice : " c
done
echo "done!"
- case、函数、函数参数使用方法
#!/bin/bash
function print()
{
echo "Your choice is $1"
}
case $1 in
"one")
#echo "one"
print 1
;;
"two")
#echo "two"
print 2
;;
"three")
#echo "othre"
print 3
;;
*)
echo "Usage $0 {one|two|three}"
;;
esac
- shell脚本中执行命令的方法
#!/bin/bash
str=$(whoami) #或者:str=`whoami`(这里的引号为反引号——ESC下面那个键)
echo $str
- shell脚本中for的使用方法
循环读取字符串中的每一个子串(以空格隔开)
#!/bin/bash
string="Waiting for a while"
for str in ${string}
do
echo $str
done
循环读取字符串中的每一个子串(以空格隔开)
#!/bin/bash
for str in "Waiting for a while"
do
echo $str
done
循环读取ls命令返回结果的每一个
#!/bin/bash
for str in `ls`
do
echo $str
done
循环次数的例子,for(())是bash支持的
#!/bin/bash
for ((i=0; i<10; i++)) #或者:for i in {1..10}
do
echo $i
done
- dirname 命令与脚本语句$(dirname "${0}")
显示指定路径除了最后的文件名或者目录名之外的路径前缀,即截取给定路径的目录部分。例如:dirname /usr/bin/sort 得到/usr/bin。
在shell脚本中经常看到这样的语句:$(dirname "${0}")
说明:${0}表示当前脚本的第一个参数,即程序的完整路径,再执行dirname命令,则取得当前脚本所在的目录。
还有语句:cd $(dirname "$0") || exit 1
说明:$(dirname "$0")表示当前脚本所在的目录,cd即进入脚本所在目录,失败则exit 1(退出)。
还有常用的获取当前脚本文件所在目录的方式:
THIS_DIR=$(cd "$(dirname $0)"; pwd)
或者是:
THIS_DIR=$(readlink -f "$(dirname "${0}")")
- grep妙用
NUM_JOBS="$(grep -c "^processor" /proc/cpuinfo)"
文件/proc/cpuinfo是cpu的信息,grep -c只统计查询结果的行数但是不输出,正则表达式"^processor"表示以processor开始的行,查看/proc/cpuinfo文件可以看出processor开始的行是cpu的第几个核心的信息。综上可知上面的shell语句就是统计了当前机器的cpu核心数目。
- 判断字符串是否是数
function isDigit()
{
if [ $# == 1 ];then
if [ `echo $1 | grep -P "^\d+$" | wc -l` == 1 ];then
return 0;
fi
fi
return 1;
}
isDigit '111'
echo $?
isDigit 'ass'
echo $?
- apache httpd自动编译生成的小脚本
脚本功能很简单,先判断当前目录中是否有Makefile文件,有则执行make进行编译生成,否则执行./configure(默认该文件存在,可以加上一条判断语句)生成Makefile文件,再进行判断和执行,过程中用MAKE_RES记录make执行的返回值,最终打印出该值。
#!/bin/bash
MAKE_RES=255 # 记录make的返回值,默认失败
if [ -f Makefile ];then # 测试Makefile文件是否存在
make # 执行make
MAKE_RES=$? # 保存make的返回值
else # 如果Makefile文件不存在,则执行configure
./configure --with-included-apr --with-pcr
if [ -f Makefile ];then # 判断是否生成了Makefile文件
make
MAKE_RES=$?
else
echo "./configure failed!"
fi
fi
echo "Make result : "${MAKE_RES} # 输出make的返回值(0表示成功,其他表示失败)
- 判断用户输入的字符串是否为“Yes”或“No”(包含各种大小写字母组合)
case "$OPT" in
[Oo][Nn]) CMD='YES';;
[Oo][Ff][Ff]) CMD='NO';;
*)
echo '选项格式错误! 请用on 或off 来切换匿名登录的开关。'
exit 1
;;
esac
- for循环一例
#! /bin/bash
DIR="/var"
cd ${DIR}
for f in $(ls ${DIR})
do
[ -d $f ] && du -s $f
done
该脚本用来列出/var目录下各子目录占用磁盘空间的大小。
- 脚本中用sudo执行命令,怎样自动输入密码,以免脚本执行中断等待用户输入密码
echo "password" | sudo -S netstat -tlnp
The -S (stdin) option causes sudo to read the password from the standard input instead of the terminal device.
The -S (stdin) option causes sudo to read the password from the standard input instead of the terminal device.
- 系统/etc/profile 中的一段代码,可以学习借鉴
<span style="font-size:12px;">if [ -d /etc/profile.d ]; then
for i in /etc/profile.d/*.sh; do #×××
if [ -r $i ]; then
. $i
fi
done
unset i
fi</span>
经常会有这样的需求:获取某个路径下的所有文件或者某些匹配的文件,然后做某种操作。以前的做法是先用find或者ls+grep的方式获取结果,然后再对结果进行循环操作,例如:result=$(find /etc/profile.d/ -name *.sh) 或者 result=$(ls /etc/profile.d/ | grep ".sh$")。今天开了一下/etc/下的配置文件profile,看到如上的一段代码,其中#×××的语句值得借鉴,根本不需要查找!!!
- 一个简单的例子,包含我写脚本的基本框架,以后可以复用
#! /bin/bash
###############################################################################
# author: andy <44452114@qq.com>
# date: 04/24/2014
# descrp: 脚本功能为列出给定目录中所有的文件和目录,通过参数形式给定需要查询
# 的目录。运行方式如下:
# $ ./list_dir.sh /home/andy
#
###############################################################################
# 判断输入参数是否合法
if [[ $# < 1 ]]; then
echo "[Error] Too few parameters!"
exit 1
fi
# 获得输入的参数
dir=$1
if [ ! -d $dir ]; then
echo "[Error] The path you give($dir) not exist!"
exit 2
fi
# 程序功能实现
list=$(ls $dir)
for item in $list
do
echo "item : $item"
done
# 结束提示
echo "Ok!"
- 对目录中所有文件求md5值并输出到文件
sudo find . -type f -print0 | xargs -0 md5sum | grep -v "\./md5sum.txt" > md5sum.txt
- 命名临时文件
$$是Script 的进程编号,利用$$组成临时文件名,这样,可避免不同的Script 开启重复的临时文件。
- 一个例子
strace -f -o /tmp/log ./configure
部分log文件文件如下:
32171 mmap2(NULL, 126192, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76e0000
32171 close(3) = 0
32171 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
32171 open("/lib/i386-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
32171 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320\n\0\0004\0\0\0"..., 512) = 512
32171 fstat64(3, {st_mode=S_IFREG|0644, st_size=13856, ...}) = 0
32171 mmap2(NULL, 16512, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb76db000
32171 mmap2(0xb76de000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0xb76de000
32171 close(3) = 0
32171 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
32171 open("/lib/i386-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
32171 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0F\0\0004\0\0\0"..., 512) = 512
32171 fstat64(3, {st_mode=S_IFREG|0644, st_size=280108, ...}) = 0
在使用下面的脚本分析,提取出依赖的软件包及版本,脚本如下(重要的地方加了注释):
for x in `dpkg -S $(grep open ./log|\
perl -pe 's!.* open\(\"([^\"]*).*!$1!' |\
grep "^/"| sort | uniq|\
grep -v "^\(/tmp\|/dev\|/proc\)" ) 2>/dev/null|\
cut -f1 -d":"| sort | uniq`; \
do
echo -n "$x (>=" `dpkg -s $x|grep ^Version|cut -f2 -d":"` "), ";
done
# 注释说明
# 1行:找到含有open的行;
# 2行:perl -pe 's!!!'或者perl -pe 's///',替换字符串。这里实际上是为了得到$1,例如:
# 上面log的第4行,会提取得到:/lib/i386-linux-gnu/libdl.so.2,注意读一下其中的正则匹配,
# 匹配open后面“”中的内容保存在$1;
# 3行:提取/开头的行;
# 4行:去掉/tmp,/dev,/proc开始的行,即不处理/tmp,/dev,/proc开头的文件。注意这里有grep使用
# 的技巧——查询多个字符串匹配:grep "\(aaa\|bbb\))
# 另外,dpkg -S 查询某个文件属于哪个debian包,dpkg -s 查询debian包的详细信息。