高级Bash脚本编程指南(32):混杂命令(一)
成于坚持,败于止步
一些不好归类的命令
jot, seq
这些工具用来生成一系列整数, 用户可以指定生成范围.
每个产生出来的整数一般都占一行, 但是可以使用-s选项来改变这种设置.
root@ubuntu:~/resource/shell-study/0624-2013# seq 5
1
2
3
4
5
root@ubuntu:~/resource/shell-study/0624-2013# seq -s : 5
1:2:3:4:5
root@ubuntu:~/resource/shell-study/0624-2013#
一个实例:使用seq命令来产生循环参数
#!/bin/bash
# 使用"seq"
echo
for a in `seq 20` # or for a in $( seq 80 )
# 与 for a in 1 2 3 4 5 ... 20 相同(少敲了好多字!).
# 也可以使用'jot'(如果系统上有的话).
do
echo -n "$a "
done # 1 2 3 4 5 ... 20
# 这也是一个通过使用命令输出
# 来产生"for"循环中[list]列表的例子.
echo; echo
COUNT=20 # 当然, 'seq'也可以使用一个可替换的参数.
for a in `seq $COUNT` # 或者 for a in $( seq $COUNT )
do
echo -n "$a "
done # 1 2 3 4 5 ... 20
echo; echo
BEGIN=15
END=20
for a in `seq $BEGIN $END`
# 传给"seq"两个参数, 从第一个参数开始增长,
#+ 一直增长到第二个参数为止.
do
echo -n "$a "
done # 15 16 17 18 19 20
echo; echo
BEGIN=45
INTERVAL=5
END=80
for a in `seq $BEGIN $INTERVAL $END`
# 传给"seq"三个参数, 从第一个参数开始增长,
#+ 并以第二个参数作为增量,
#+ 一直增长到第三个参数为止.
do
echo -n "$a "
done # 45 50 55 60 65 70 75 80
echo; echo
exit 0
结果:
root@ubuntu:~/resource/shell-study/0624-2013# chmod +x test1.sh
root@ubuntu:~/resource/shell-study/0624-2013# ./test1.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
15 16 17 18 19 20
45 50 55 60 65 70 75 80
root@ubuntu:~/resource/shell-study/0624-2013#
另一个小例子:
# 产生10个连续扩展名的文件,
#+ 名字分别是 file.1, file.2 . . . file.10.
COUNT=10
PREFIX=file
for filename in `seq $COUNT`
do
touch $PREFIX.$filename
# 或者, 你可以做一些其他的操作,
#+ 比如rm, grep, 等等.
done
接着看一个实例:字母统计
#!/bin/bash
# 统计一个文本文件中某些字母出现的次数.
# 由Stefano Palmeri所编写.
# 经过授权可以使用在本书中.
# 本书作者做了少许修改.
MINARGS=2 # 本脚本至少需要2个参数.
E_BADARGS=65
FILE=$1
let LETTERS=$#-1 # 指定了多少个字母(作为命令行参数).
# (从命令行参数的个数中减1.)
show_help(){
echo
echo Usage: `basename $0` file letters
echo Note: `basename $0` arguments are case sensitive.
echo Example: `basename $0` foobar.txt G n U L i N U x.
echo
}
# 检查参数个数.
if [ $# -lt $MINARGS ]; then
echo
echo "Not enough arguments."
echo
show_help
exit $E_BADARGS
fi
# 检查文件是否存在.
if [ ! -f $FILE ]; then
echo "File \"$FILE\" does not exist."
exit $E_BADARGS
fi
# 统计字母出现的次数.
for n in `seq $LETTERS`; do
shift
if [[ `echo -n "$1" | wc -c` -eq 1 ]]; then # 检查参数.
echo "$1" -\> `cat $FILE | tr -cd "$1" | wc -c` # 统计.
else
echo "$1 is not a single char."
fi
done
exit $?
结果:
root@ubuntu:~/resource/shell-study/0624-2013# ./test2.sh test1.sh h d
h -> 14
d -> 8
root@ubuntu:~/resource/shell-study/0624-2013#
getopt
getopt命令将会分析以破折号开头的命令行选项,这个外部命令与Bash的内建命令getopts作用相同,通过使用-l标志, getopt可以处理超长(多个字符的)选项, 并且也允许参数重置.
一个实例:使用getopt来分析命令行选项
#!/bin/bash
# 使用getopt.
E_OPTERR=65
if [ "$#" -eq 0 ]
then # 脚本需要至少一个命令行参数.
echo "Usage $0 -[options a,b,c]"
exit $E_OPTERR
fi
set -- `getopt "abcd:" "$@"`
# 为命令行参数设置位置参数.
# 如果使用"$*"来代替"$@"的话, 会发生什么?
while [ ! -z "$1" ]
do
case "$1" in
-a) echo "Option \"a\"";;
-b) echo "Option \"b\"";;
-c) echo "Option \"c\"";;
-d) echo "Option \"d\" $2";;
*) break;;
esac
shift
done
# 通常来说在脚本中使用内建的'getopts'命令,
#+ 会比使用'getopt'好一些.
# 参考"ex33.sh".
exit 0
结果:
root@ubuntu:~/resource/shell-study/0624-2013# chmod +x test3.sh
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh -a
Option "a"
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh -abc
Option "a"
Option "b"
Option "c"
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh -a -b -c
Option "a"
Option "b"
Option "c"
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh -d
getopt: option requires an argument -- 'd'
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh -dXYZ
Option "d" XYZ
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh -d XYZ
Option "d" XYZ
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh -abcd
getopt: option requires an argument -- 'd'
Option "a"
Option "b"
Option "c"
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh -abcdZ
Option "a"
Option "b"
Option "c"
Option "d" Z
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh -z
getopt: invalid option -- 'z'
root@ubuntu:~/resource/shell-study/0624-2013# ./test3.sh a
root@ubuntu:~/resource/shell-study/0624-2013#
run-parts
run-parts命令将会执行目标目录中所有的脚本, 这些脚本会以ASCII码的循序进行排列. 当然, 这些脚本都需要具有可执行权限.
yes
yes命令的默认行为是向stdout连续不断的输出字符y, 每个y单独占一行. 可以使用control-c来结束输出. 如果想换一个输出字符的话, 可以使用yes different string, 这样就会连续不断的输出different string到stdout. 那么这样的命令究竟能用来做什么呢? 在命令行或者脚本中, yes的输出可以通过重定向或管道来传递给一些命令, 这些命令的特点是需要用户输入来进行交互. 事实上, 这个命令可以说是expect命令
yes | fsck /dev/hda1将会以非交互的形式运行fsck(因为需要用户输入的y全由yes命令搞定了)(小心使用!).
yes | rm -r dirname 与 rm -rf dirname 效果相同(小心使用!).
当用yes命令的管道形式来使用一些可能具有潜在危险的系统命令的时候一定要深思熟虑, 比如fsck或fdisk. 可能会产生一些令人意外的副作用.
yes命令也可用来分析变量. 比如:
bash$ yes $BASH_VERSION
3.00.16(1)-release
3.00.16(1)-release
3.00.16(1)-release
3.00.16(1)-release
3.00.16(1)-release
. . .
这个"特性"估计也不会特别有用,实在是没有什么让我感觉特别有用,知道就好
banner
将会把传递进来的参数字符串用一个ASCII字符(默认是'#')给画出来(就是将多个'#'拼出一副字符的图形), 然后输出到stdout. 可以作为硬拷贝重定向到打印机上. (译者注: 可以使用-w 选项设置宽度.)
printenv
显示某个特定用户所有的环境变量.
root@ubuntu:~/resource/shell-study# printenv
ORBIT_SOCKETDIR=/tmp/orbit-root
SSH_AGENT_PID=1792
SHELL=/bin/bash
TERM=xterm
XDG_SESSION_COOKIE=e2701cc9fa08772c6d472e6450b8b925-1371736987.528568-974417364
WINDOWID=58778621
GNOME_KEYRING_CONTROL=/tmp/keyring-sii09y
GTK_MODULES=canberra-gtk-module
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:hl=44;37:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:
SSH_AUTH_SOCK=/tmp/keyring-sii09y/ssh
USERNAME=root
SESSION_MANAGER=local/ubuntu:@/tmp/.ICE-unix/1757,unix/ubuntu:/tmp/.ICE-unix/1757
DEFAULTS_PATH=/usr/share/gconf/gnome.default.path
XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome:/etc/xdg
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/java/jdk1.7.0_13/bin:/opt/FriendlyARM/toolschain/4.4.3/bin:/opt/FriendlyARM/toolschain/4.4.3/bin:/opt/FriendlyARM/toolschain/4.4.3/bin:/opt/FriendlyARM/toolschain/4.4.3/bin
DESKTOP_SESSION=gnome
PWD=/root/resource/shell-study
JAVA_HOME=/usr/lib/jvm/java/jdk1.7.0_13
GDM_KEYBOARD_LAYOUT=us
GNOME_KEYRING_PID=1739
LANG=en_US.UTF-8
GDM_LANG=en_US.UTF-8
MANDATORY_PATH=/usr/share/gconf/gnome.mandatory.path
GDMSESSION=gnome
SPEECHD_PORT=6560
HOME=/root
SHLVL=4
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LOGNAME=root
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-HNEc911F8I,guid=b1137a22c401c60a5e2f5d6f51c30b9b
CLASSPATH=.:/usr/lib/jvm/java/jdk1.7.0_13/lib
XDG_DATA_DIRS=/usr/share/gnome:/usr/local/share/:/usr/share/
LESSOPEN=| /usr/bin/lesspipe %s
DISPLAY=:0.0
LESSCLOSE=/usr/bin/lesspipe %s %s
COLORTERM=gnome-terminal
XAUTHORITY=/var/run/gdm/auth-for-root-DCvPim/database
_=/usr/bin/printenv
OLDPWD=/root/resource
root@ubuntu:~/resource/shell-study#
lp
lp和lpr命令将会把文件发送到打印队列中, 并且作为硬拷贝来打印.这些命令会记录它们名字的起点, 直到行打印机的另一个阶段.
bash$ lp file1.txt 或者 bash$ lp <file1.txt
通常情况下都是将pr的格式化输出传递到lp中.
bash$ pr -options file1.txt | lp
格式化的包, 比如groff和Ghostscript就可以将它们的输出直接发送给lp.
bash$ groff -Tascii file.tr | lp
bash$ gs -options | lp file.ps
还有一些相关的命令, 比如lpq, 可以用来查看打印队列, 而lprm, 可以从打印队列中删除作业.
tee
这是一个重定向操作, 但是与之前所看到的有点不同. 就像管道中的"三通"一样, 这个命令可以将命令或者管道命令的输出"抽出"到一个文件中, 而且不影响结果. 当你想将一个运行中进程的输出保存到文件时, 或者为了debug而保存输出记录的时候, 这个命令就显得非常有用了.
|----> 到文件
|
==========================|====================
命令 ---> 命令 ---> |tee ---> 命令 ---> ---> 管道的输出
===============================================
也就是说log信息可以同时打印出来和保存到file中
root@ubuntu:~/resource/shell-study# ls > file
root@ubuntu:~/resource/shell-study# ls
0426-2013 0506-2013 0509-2013 0614-2013 0619-2013 0622-2013 file
0427-2013 0507-2013 0609-2013 0615-2013 0620-2013 0624-2013
0504-2013 0508-2013 0613-2013 0618-2013 0621-2013 0626-2013
root@ubuntu:~/resource/shell-study# rm file
root@ubuntu:~/resource/shell-study# ls
0426-2013 0506-2013 0509-2013 0614-2013 0619-2013 0622-2013
0427-2013 0507-2013 0609-2013 0615-2013 0620-2013 0624-2013
0504-2013 0508-2013 0613-2013 0618-2013 0621-2013 0626-2013
root@ubuntu:~/resource/shell-study# ls | tee file
0426-2013
0427-2013
0504-2013
0506-2013
0507-2013
0508-2013
0509-2013
0609-2013
0613-2013
0614-2013
0615-2013
0618-2013
0619-2013
0620-2013
0621-2013
0622-2013
0624-2013
0626-2013
root@ubuntu:~/resource/shell-study# ls
0426-2013 0506-2013 0509-2013 0614-2013 0619-2013 0622-2013 file
0427-2013 0507-2013 0609-2013 0615-2013 0620-2013 0624-2013
0504-2013 0508-2013 0613-2013 0618-2013 0621-2013 0626-2013
root@ubuntu:~/resource/shell-study# cat file
0426-2013
0427-2013
0504-2013
0506-2013
0507-2013
0508-2013
0509-2013
0609-2013
0613-2013
0614-2013
0615-2013
0618-2013
0619-2013
0620-2013
0621-2013
0622-2013
0624-2013
0626-2013
root@ubuntu:~/resource/shell-study#
cat listfile* | sort | tee check.file | uniq > result.file
上面的语句在对排序的结果进行uniq(去掉重复行)之前, 文件check.file保存了排过序的"listfiles".
mkfifo
这个不大引人注意的命令可以创建一个命名管道, 并产生一个临时的先进先出的buffer, 用来在两个进程之间传递数据. [3] 典型的应用是一个进程向FIFO中写数据, 另一个进程读出来
pathchk
这个命令用来检查文件名的有效性. 如果文件名超过了最大允许长度(255个字符), 或者它所在的一个或多个路径搜索不到, 那么就会产生一个错误结果.不幸的是, pathchk并不能够返回一个可识别的错误码, 因此它在脚本中几乎没有什么用.
先到这里了,O(∩_∩)O~
我的专栏地址:http://blog.csdn.net/column/details/shell-daily-study.html
待续。。。。