高级Bash脚本编程指南(23):复杂命令
成与坚持,败于止步
更高级的用户命令
find
find命令的一般格式:
find pathname -options [-exec]
pathname 是find命令所查找的目录路径
-exec 对匹配的文件执行该参数所给出的shell命令
-options 选项参数:
-name 按照文件名查找文件
-perm 按照文件权限来查找文件
-user 按照文件属主来查找文件
-group 按照文件所属组来查找文件
-mtime -n +n 按照文件的更改时间来查找文件,-n 表示n天以内,+n 表示n天前
-nogroup 查找无属组的文件
-nouser 查找无属主的文件
-type 查找某一类型的文件:
b 块设备文件
d 目录
c 字符设备文件
p 管道文件
l 符号链接文件
f 普通文件
-iregex 忽略大小写的正则表达式
-regex 正则表达式
应用举例
root@ubuntu:~/resource/shell-study# find ~/resource/shell-study -name '*.txt'
/root/resource/shell-study/0509-2013/test7/3.txt
/root/resource/shell-study/0507-2013/file.txt
/root/resource/shell-study/0426-2013/txt-folder/file2.txt
/root/resource/shell-study/0426-2013/txt-folder/file1.txt
/root/resource/shell-study/0506-2013/file.txt
root@ubuntu:~/resource/shell-study#
比较特殊的情况,使用exec来执行shell命令,格式要求:
-exec COMMAND \;
-exec 选项后面跟随着所要执行的命令,然后是一对{}一个空格和一个/,最后是一个分号。
在每一个find匹配到的文件执行COMMAND命令. 命令序列以;结束(";"是转义符以保证shll传递到find命令中的字符不会被解释为其他的特殊字符).
如果COMMAND中包含{}, 那么find命令将会用所有匹配文件的路径名来替换"{}".
例:在用户主目录下查找修改时间在3天前的“.txt”文件并删除
$find . -mtime +3 -name “*.txt” -exec rm {} /;
以下列出find的应用举例:
find /home/bozo/projects -mtime 1
# 列出最后一天被修改的
#+ 在/home/bozo/projects目录树下的所有文件.
#
# mtime = 目标文件最后修改的时间
# ctime = 修改后的最后状态(通过'chmod'或其他方法)
# atime = 最后访问时间
DIR=/home/bozo/junk_files
find "$DIR" -type f -atime +5 -exec rm {} \;
# ^^
# 大括号就是"find"命令用来替换目录的地方.
#
# 删除至少5天内没被访问过的
#+ "/home/bozo/junk_files" 中的所有文件.
#
# "-type filetype", where
# f = regular file
# d = directory, etc.
# ('find' 命令的man页包含有完整的选项列表.)
find /etc -exec grep \
'[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*' {} \;
# 在 /etc 目录中的文件找到所所有包含 IP 地址(xxx.xxx.xxx.xxx) 的文件.
# 可能会查找到一些多余的匹配. 我们如何去掉它们呢?
# 或许可以使用如下方法:
find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
| grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'
#
# [:digit:] 是一种字符类.
第三个实例也许比不那么容易理解,没关系,不要着急,会好的,O(∩_∩)O~,先列出tr的用法
tr(translate缩写)主要用于删除文件中的控制字符,或进行字符转换。
语法: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
接下来看一个实例, 糟糕的文件名, 删除当前目录下文件名中包含一些糟糕字符(包括空白的文件.
#!/bin/bash
# badname.sh
# 删除当前目录下文件名中包含一些特殊字符的文件.
# (这些特殊字符指的是不应该出现在文件名中的字符)
for filename in *
do
badname=`echo "$filename" | sed -n /[\+\{\;\"\\\=\?~\(\)\<\>\&\*\|\$]/p`
# badname=`echo "$filename" | sed -n '/[+{;"\=?~()<>&*|$]/p'` 这句也行.
# 删除文件名包含这些字符的文件: + { ; " \ = ? ~ ( ) < > & * | $
#
rm $badname 2>/dev/null
# ^^^^^^^^^^^ 错误消息将被抛弃.
done
# 现在, 处理文件名中以任何方式包含空白的文件.
find . -name "* *" -exec rm -f {} \;
# "find"命令匹配到的目录名将替换到"{}"的位置.
# '\'是为了保证';'被正确的转义, 并且放到命令的结尾.
exit 0
#---------------------------------------------------------------------
# 这行下边的命令将不会运行, 因为有 "exit" 命令.
# 下边这句可以用来替换上边的脚本:
find . -name '*[+{;"\\=?~()<>&*|$ ]*' -exec rm -f '{}' \;
首先要理解上面的实例,你需要知道sed这个命令了
sed编辑器逐行处理输入,然后把结果发送到屏幕。
-i选项:直接作用源文件,源文件将被修改。
sed命令和选项:
a\ 在当前行后添加一行或多行
c\ 用新文本替换当前行中的文本
d 删除行
i\ 在当前行之前插入文本
h 把模式空间的内容复制到暂存缓冲区
H 把模式空间的内容添加到缓冲区
g 取出暂存缓冲区的内容,将其复制到模式缓冲区
G 取出暂存缓冲区的内容,将其追加到模式缓冲区
l 列出非打印字符
p 打印行
n 读入下一行输入,并从下一条而不是第一条命令对其处理
q 结束或退出sed
r 从文件中读取输入行
! 对所选行以外的行应用所有命令
s 用一个字符串替换另外一个字符串
替换标志:
g 在行内进行全局替换
p 打印行
w 将行写入文件
x 交换暂存缓冲区和模式空间的内容
y 将字符转换成另外一个字符
sed例子:
打印:p命令
sed ‘/abc/p’ file 打印file中包含abc的行。默认情况sed把所有行都打印到屏幕,如果某行匹配到模式,则把该行另外再打印一遍
sed -n ‘/abc/p’ file 和上面一样,只是去掉默认情况sed把所有行都打印到屏幕这个操作
接下来看一个实例:通过文件的inode号来删除文件
#!/bin/bash
# 当文件名以一个非法字符开头的时候, 这就非常有用了,
#+ 比如 ? 或 -.
ARGCOUNT=1 # 文件名参数必须被传递到脚本中.
E_WRONGARGS=70
E_FILE_NOT_EXIST=71
E_CHANGED_MIND=72
if [ $# -ne "$ARGCOUNT" ]
then
echo "Usage: `basename $0` filename"
exit $E_WRONGARGS
fi
if [ ! -e "$1" ]
then
echo "File \""$1"\" does not exist."
exit $E_FILE_NOT_EXIST
fi
inum=`ls -i | grep "$1" | awk '{print $1}'`
# inum = inode 文件的(索引节点)号.
# --------------------------------------------------------
# 每个文件都有一个inode号, 这个号用来记录文件物理地址信息.
# --------------------------------------------------------
echo; echo -n "Are you absolutely sure you want to delete \"$1\" (y/n)? "
# 'rm' 命令的 '-v' 选项得询问也会出现这句话.
read answer
case "$answer" in
[nN]) echo "Changed your mind, huh?"
exit $E_CHANGED_MIND
;;
*) echo "Deleting file \"$1\".";;
esac
find . -inum $inum -exec rm {} \;
# ^^
# 大括号就是"find"命令
#+ 用来替换文本输出的地方.
echo "File "\"$1"\" deleted!"
exit 0
结果:
root@ubuntu:~/resource/shell-study/0618-2013# touch file1
root@ubuntu:~/resource/shell-study/0618-2013# ls
file1 test1.sh
root@ubuntu:~/resource/shell-study/0618-2013# chmod +x test1.sh
root@ubuntu:~/resource/shell-study/0618-2013# ./test1.sh file1
Are you absolutely sure you want to delete "file1" (y/n)? y
Deleting file "file1".
File "file1" deleted!
root@ubuntu:~/resource/shell-study/0618-2013#
上面的实例也许你不明白下面这一句的含义
inum=`ls -i | grep "$1" | awk '{print $1}'`
也许这样会更有助于你的理解
root@ubuntu:~/resource/shell-study/0618-2013# touch file1
root@ubuntu:~/resource/shell-study/0618-2013# ls
file1 test1.sh
root@ubuntu:~/resource/shell-study/0618-2013# ls -i
695725 file1 695724 test1.sh
root@ubuntu:~/resource/shell-study/0618-2013# ls -i | grep file1
695725 file1
root@ubuntu:~/resource/shell-study/0618-2013# ls -i | grep file1 | awk '{print $1}'
695725
root@ubuntu:~/resource/shell-study/0618-2013#
见到了多了你自然就会了,不要着急,O(∩_∩)O~
xargs
这是给命令传递参数的一个过滤器, 也是组合多个命令的一个工具. 它把一个数据流分割为一些足够小的块, 以方便过滤器和命令进行处理. 由此这个命令也是后置引用的一个强有力的替换. 当在一般情况下使用过多参数的命令替换都会产生失败的现象, 这时候使用xargs命令来替换, 一般都能成功. 一般的, xargs从stdin或者管道中读取数据, 但是它也能够从文件的输出中读取数据.
xargs的默认命令是echo. 这意味着通过管道传递给xargs的输入将会包含换行和空白, 不过通过xargs的处理, 换行和空白将被空格取代.
root@ubuntu:~/resource/shell-study/0618-2013# ls -l
total 4
-rw-r--r-- 1 root root 0 2013-06-18 03:35 file1
-rwxr-xr-x 1 root root 1178 2013-06-18 03:31 test1.sh
root@ubuntu:~/resource/shell-study/0618-2013# ls -l | xargs
total 4 -rw-r--r-- 1 root root 0 2013-06-18 03:35 file1 -rwxr-xr-x 1 root root 1178 2013-06-18 03:31 test1.sh
root@ubuntu:~/resource/shell-study/0618-2013# find . -type f | xargs grep "echo"
./test1.sh: echo "Usage: `basename $0` filename"
./test1.sh: echo "File \""$1"\" does not exist."
./test1.sh:echo; echo -n "Are you absolutely sure you want to delete \"$1\" (y/n)? "
./test1.sh:[nN]) echo "Changed your mind, huh?"
./test1.sh:*) echo "Deleting file \"$1\".";;
./test1.sh:echo "File "\"$1"\" deleted!"
root@ubuntu:~/resource/shell-study/0618-2013#
对第三条命令进行拆解,过程如下:
root@ubuntu:~/resource/shell-study/0618-2013# find . -type f
./test1.sh
./file1
root@ubuntu:~/resource/shell-study/0618-2013# grep "echo" ./test1.sh
echo "Usage: `basename $0` filename"
echo "File \""$1"\" does not exist."
echo; echo -n "Are you absolutely sure you want to delete \"$1\" (y/n)? "
[nN]) echo "Changed your mind, huh?"
*) echo "Deleting file \"$1\".";;
echo "File "\"$1"\" deleted!"
root@ubuntu:~/resource/shell-study/0618-2013# grep "echo" ./file1
root@ubuntu:~/resource/shell-study/0618-2013#
s | xargs -p -l gzip 使用gzips压缩当前目录下的每个文件, 每次压缩一个, 并且在每次压缩前都提示用户.
一个有趣的xargs选项是-n NN, NN用来限制每次传递进来参数的个数.ls | xargs -n 8 echo以每行8列的形式列出当前目录下的所有文件.
root@ubuntu:~/resource/shell-study/0618-2013# ls -l | xargs echo
total 4 -rw-r--r-- 1 root root 0 2013-06-18 03:35 file1 -rwxr-xr-x 1 root root 1178 2013-06-18 03:31 test1.sh
root@ubuntu:~/resource/shell-study/0618-2013# ls -l | xargs -n 8 echo
total 4 -rw-r--r-- 1 root root 0 2013-06-18
03:35 file1 -rwxr-xr-x 1 root root 1178 2013-06-18
03:31 test1.sh
root@ubuntu:~/resource/shell-study/0618-2013# ls | xargs -p -l gzip
gzip file1 ?...n
gzip test1.sh ?...n
gzip ?...n
root@ubuntu:~/resource/shell-study/0618-2013#
使用xargs来监控系统log
#!/bin/bash
# 从/var/log/messagesGenerates的尾部开始
# 产生当前目录下的一个lof文件.
# 注意: 如果这个脚本被一个一般用户调用的话,
# /var/log/messages 必须是全部可读的.
# #root chmod 644 /var/log/messages
LINES=5
( date; uname -a ) >>logfile
# 时间和机器名
echo ----------------------------------------------------- >>logfile
tail -$LINES /var/log/messages | xargs | fmt -s >>logfile
echo >>logfile
echo >>logfile
exit 0
结果:
root@ubuntu:~/resource/shell-study/0618-2013# chmod +x test2.sh
root@ubuntu:~/resource/shell-study/0618-2013# ls
file1 test1.sh test2.sh
root@ubuntu:~/resource/shell-study/0618-2013# ./test2.sh
root@ubuntu:~/resource/shell-study/0618-2013# ls
file1 logfile test1.sh test2.sh
root@ubuntu:~/resource/shell-study/0618-2013# cat logfile
Tue Jun 18 04:01:14 PDT 2013
Linux ubuntu 2.6.32-21-generic #32-Ubuntu SMP Fri Apr 16 08:10:02 UTC 2010 i686 GNU/Linux
-----------------------------------------------------
Jun 13 02:45:31 ubuntu kernel: [72501.550212] usb 2-2.1: configuration
#1 chosen from 1 choice Jun 13 17:49:43 ubuntu kernel: [81810.618878]
usb 2-2.1: USB disconnect, address 13 Jun 13 17:49:43 ubuntu kernel:
[81811.143471] usb 2-2.1: new full speed USB device using uhci_hcd and
address 14 Jun 13 17:49:43 ubuntu kernel: [81811.267228] usb 2-2.1:
configuration #1 chosen from 1 choice Jun 14 03:04:53 ubuntu kernel:
[99875.994737] usb 2-2.1: USB disconnect, address 14
root@ubuntu:~/resource/shell-study/0618-2013#
部分命令拆解:
root@ubuntu:~/resource/shell-study# tail -5 /var/log/messages | xargs
Jun 13 17:49:43 ubuntu kernel: [81810.618878] usb 2-2.1: USB disconnect, address 13 Jun 13 17:49:43 ubuntu kernel: [81811.143471] usb 2-2.1: new full speed USB device using uhci_hcd and address 14 Jun 13 17:49:43 ubuntu kernel: [81811.267228] usb 2-2.1: configuration #1 chosen from 1 choice Jun 14 03:04:53 ubuntu kernel: [99875.994737] usb 2-2.1: USB disconnect, address 14 Jun 18 04:03:34 ubuntu kernel: [118985.358071] hrtimer: interrupt took 15168861 ns
root@ubuntu:~/resource/shell-study# tail -5 /var/log/messages | xargs | fmt -s
Jun 13 17:49:43 ubuntu kernel: [81810.618878] usb 2-2.1: USB disconnect,
address 13 Jun 13 17:49:43 ubuntu kernel: [81811.143471] usb 2-2.1:
new full speed USB device using uhci_hcd and address 14 Jun 13 17:49:43
ubuntu kernel: [81811.267228] usb 2-2.1: configuration #1 chosen from
1 choice Jun 14 03:04:53 ubuntu kernel: [99875.994737] usb 2-2.1: USB
disconnect, address 14 Jun 18 04:03:34 ubuntu kernel: [118985.358071]
hrtimer: interrupt took 15168861 ns
root@ubuntu:~/resource/shell-study#
另外一个实例:把当前目录下的文件拷贝到另一个文件中
#!/bin/bash
# 将当前目录下($PWD)的所有文件都拷贝到
#+ 命令行所指定的另一个目录中去.
E_NOARGS=65
if [ -z "$1" ] # 如果没有参数传递进来那就退出.
then
echo "Usage: `basename $0` directory-to-copy-to"
exit $E_NOARGS
fi
ls . | xargs -i -t cp ./{} $1
# ^^ ^^ ^^
# -t 是 "verbose" (输出命令行到stderr) 选项.
# -i 是"替换字符串"选项.
# {} 是输出文本的替换点.
# 这与在"find"命令中使用{}的情况很相像.
#
# 列出当前目录下的所有文件(ls .),
#+ 将 "ls" 的输出作为参数传递到 "xargs"(-i -t 选项) 中,
#+ 然后拷贝(cp)这些参数({})到一个新目录中($1).
#
# 最终的结果和下边的命令等价,
#+ cp * $1
#+ 除非有文件名中嵌入了"空白"字符.
exit 0
结果:
root@ubuntu:~/resource/shell-study/0618-2013# ls
file1 logfile test1.sh test2.sh test3.sh
root@ubuntu:~/resource/shell-study/0618-2013# cd ..
root@ubuntu:~/resource/shell-study# ls
0426-2013 0427-2013 0504-2013 0506-2013 0507-2013 0508-2013 0509-2013 0609-2013 0613-2013 0614-2013 0615-2013 0618-2013
root@ubuntu:~/resource/shell-study# mkdir tests
root@ubuntu:~/resource/shell-study# ls
0426-2013 0427-2013 0504-2013 0506-2013 0507-2013 0508-2013 0509-2013 0609-2013 0613-2013 0614-2013 0615-2013 0618-2013 tests
root@ubuntu:~/resource/shell-study# cd 0618-2013/
root@ubuntu:~/resource/shell-study/0618-2013# chmod +x test3.sh
root@ubuntu:~/resource/shell-study/0618-2013# ./test3.sh ./../tests/
cp ./file1 ./../tests/
cp ./logfile ./../tests/
cp ./test1.sh ./../tests/
cp ./test2.sh ./../tests/
cp ./test3.sh ./../tests/
root@ubuntu:~/resource/shell-study/0618-2013# cd ../tests/
root@ubuntu:~/resource/shell-study/tests# ls
file1 logfile test1.sh test2.sh test3.sh
root@ubuntu:~/resource/shell-study/tests#
继续实例:通过名字kill进程
#!/bin/bash
# 例如,
#+ 试一下 "./file.sh xterm" --
#+ 并且查看你系统上的所有xterm都将消失.
# 警告:
# -----
# 这是一个非常危险的脚本.
# 运行它的时候一定要小心. (尤其是以root身份运行时)
#+ 因为运行这个脚本可能会引起数据丢失或产生其他一些不好的效果.
E_BADARGS=66
if test -z "$1" # 没有参数传递进来?
then
echo "Usage: `basename $0` Process(es)_to_kill"
exit $E_BADARGS
fi
PROCESS_NAME="$1"
ps ax | grep "$PROCESS_NAME" | awk '{print $1}' | xargs -i kill {} 2&>/dev/null
# ^^ ^^
# -----------------------------------------------------------
# 注意:
# -i 参数是xargs命令的"替换字符串"选项.
# 大括号对的地方就是替换点.
# 2&>/dev/null 将会丢弃不需要的错误消息.
# -----------------------------------------------------------
exit $?
# 在这个脚本中, "killall"命令具有相同的效果,
#+ 但是这么做就没有教育意义了.
部分命令拆解:
root@ubuntu:~/resource/shell-study/0618-2013# ps ax
PID TTY STAT TIME COMMAND
1 ? Ss 0:01 /sbin/init
2 ? S 0:00 [kthreadd]
3 ? S 0:00 [migration/0]
4 ? S 0:00 [ksoftirqd/0]
5 ? S 0:00 [watchdog/0]
6 ? S 0:00 [events/0]
7 ? S 0:00 [cpuset]
8 ? S 0:00 [khelper]
9 ? S 0:00 [netns]
10 ? S 0:00 [async/mgr]
11 ? S 0:00 [pm]
12 ? S 0:00 [sync_supers]
13 ? S 0:00 [bdi-default]
14 ? S 0:00 [kintegrityd/0]
15 ? S 0:00 [kblockd/0]
16 ? S 0:00 [kacpid]
17 ? S 0:00 [kacpi_notify]
18 ? S 0:00 [kacpi_hotplug]
19 ? S 5:22 [ata/0]
20 ? S 0:00 [ata_aux]
21 ? S 0:00 [ksuspend_usbd]
22 ? S 0:00 [khubd]
23 ? S 0:00 [kseriod]
24 ? S 0:00 [kmmcd]
27 ? S 0:00 [khungtaskd]
28 ? S 0:00 [kswapd0]
29 ? SN 0:00 [ksmd]
30 ? S 0:00 [aio/0]
31 ? S 0:00 [ecryptfs-kthrea]
32 ? S 0:00 [crypto/0]
35 ? S 0:00 [pciehpd]
37 ? S 0:00 [scsi_eh_0]
38 ? S 0:14 [scsi_eh_1]
41 ? S 0:00 [kstriped]
42 ? S 0:00 [kmpathd/0]
43 ? S 0:00 [kmpath_handlerd]
44 ? S 0:00 [ksnapd]
45 ? S 0:00 [kondemand/0]
46 ? S 0:00 [kconservative/0]
132 ? S 0:00 [usbhid_resumer]
238 ? S 0:00 [mpt_poll_0]
240 ? S 0:00 [mpt/0]
248 ? S 0:00 [scsi_eh_2]
265 ? S 0:06 [jbd2/sda1-8]
266 ? S 0:00 [ext4-dio-unwrit]
326 ? S 0:00 upstart-udev-bridge --daemon
328 ? S<s 0:00 udevd --daemon
571 ? S 0:00 [kpsmoused]
667 ? S 0:00 [kgameportd]
721 ? Ss 0:00 portmap
746 ? Sl 0:00 rsyslogd -c4
760 ? Ss 0:03 dbus-daemon --system --fork
776 ? Ss 0:00 rpc.statd -L
778 ? Ssl 0:00 NetworkManager
782 ? S 0:00 avahi-daemon: running [ubuntu-2.local]
784 ? S 0:00 /usr/sbin/modem-manager
785 ? Ss 0:00 avahi-daemon: chroot helper
797 ? S 0:00 /sbin/wpa_supplicant -u -s
843 tty4 Ss+ 0:00 /sbin/getty -8 38400 tty4
849 tty5 Ss+ 0:00 /sbin/getty -8 38400 tty5
857 tty2 Ss+ 0:00 /sbin/getty -8 38400 tty2
858 tty3 Ss+ 0:00 /sbin/getty -8 38400 tty3
860 tty6 Ss+ 0:00 /sbin/getty -8 38400 tty6
861 ? Ss 0:00 acpid -c /etc/acpi/events -s /var/run/acpid.socket
867 ? Ss 0:00 cron
868 ? Ss 0:00 atd
876 ? S< 0:00 udevd --daemon
878 ? S 0:00 [rpciod/0]
938 ? S 0:00 [lockd]
939 ? S 0:00 [nfsd4]
940 ? S 0:00 [nfsd]
941 ? S 0:00 [nfsd]
942 ? S 0:00 [nfsd]
943 ? S 0:00 [nfsd]
944 ? S 0:00 [nfsd]
945 ? S 0:00 [nfsd]
946 ? S 0:00 [nfsd]
947 ? S 0:00 [nfsd]
951 ? Ss 0:00 /usr/sbin/rpc.mountd --manage-gids
1008 ? Ss 0:00 /usr/sbin/cupsd -C /etc/cups/cupsd.conf
1152 tty1 Ss+ 0:00 /sbin/getty -8 38400 tty1
1182 ? S 0:00 [vmmemctl]
1407 ? Ssl 0:00 /usr/sbin/vmware-vmblock-fuse -o subtype=vmware-vmblock,default_permissions,allow_other /var/run/vmblock-fuse
1427 ? S 0:39 /usr/sbin/vmtoolsd
1475 ? Ss 0:00 tpvmlpd2
1483 ? Ssl 0:00 gdm-binary
1487 ? Sl 0:00 /usr/sbin/console-kit-daemon --no-daemon
1552 ? Sl 0:00 /usr/lib/gdm/gdm-simple-slave --display-id /org/gnome/DisplayManager/Display1
1557 tty7 Rs+ 11:40 /usr/bin/X :0 -nr -verbose -auth /var/run/gdm/auth-for-gdm-VvNKCd/database -nolisten tcp vt7
1602 ? S 0:00 /usr/bin/dbus-launch --exit-with-session
1621 ? Sl 0:00 /usr/lib/gdm/gdm-session-worker
1625 ? S 0:00 /usr/lib/upower/upowerd
1629 ? SNl 0:00 /usr/lib/rtkit/rtkit-daemon
1633 ? S 0:00 /usr/lib/policykit-1/polkitd
1667 ? Ssl 0:00 /usr/sbin/hald
1668 ? S 0:00 hald-runner
1697 ? S 0:00 hald-addon-input: Listening on /dev/input/event2 /dev/input/event0
1706 ? S 0:10 hald-addon-storage: polling /dev/sr0 (every 2 sec)
1711 ? S 0:00 hald-addon-acpi: listening on acpid socket /var/run/acpid.socket
1712 ? S 0:00 hald-addon-storage: no polling on /dev/fd0 because it is explicitly disabled
1726 ? Sl 0:00 /usr/bin/gnome-keyring-daemon --daemonize --login
1744 ? Ssl 0:00 gnome-session
1779 ? Ss 0:00 /usr/bin/ssh-agent /usr/bin/dbus-launch --exit-with-session gnome-session
1782 ? S 0:00 /usr/bin/dbus-launch --exit-with-session gnome-session
1783 ? Ss 0:01 /bin/dbus-daemon --fork --print-pid 5 --print-address 7 --session
1786 ? S 0:03 /usr/lib/libgconf2-4/gconfd-2
1792 ? Ss 0:12 /usr/lib/gnome-settings-daemon/gnome-settings-daemon
1795 ? S 0:00 /usr/lib/gvfs/gvfsd
1799 ? Ssl 0:00 /usr/lib/gvfs//gvfs-fuse-daemon /root/.gvfs
1806 ? S 1:39 /usr/lib/vmware-tools/sbin32/vmtoolsd -n vmusr --blockFd 3
1808 ? S 0:00 /usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1
1811 ? S 0:00 gnome-power-manager
1813 ? S 0:45 gnome-panel
1816 ? S 0:02 nm-applet --sm-disable
1819 ? S 0:33 nautilus
1820 ? S 0:27 metacity --replace
1822 ? S 0:00 bluetooth-applet
1830 ? S 0:00 /usr/lib/gvfs/gvfs-gdu-volume-monitor
1835 ? S 0:00 /usr/lib/udisks/udisks-daemon
1836 ? S 0:04 udisks-daemon: polling /dev/sr0
1844 ? Sl 0:00 /usr/lib/gvfs/gvfs-afc-volume-monitor
1852 ? S 0:00 /usr/lib/gvfs/gvfs-gphoto2-volume-monitor
1854 ? S 0:01 /usr/lib/gvfs/gvfsd-trash --spawner :1.6 /org/gtk/gvfs/exec_spaw/0
1885 ? Ss 0:00 gnome-screensaver
1887 ? S 0:00 /usr/lib/gvfs/gvfsd-burn --spawner :1.6 /org/gtk/gvfs/exec_spaw/1
1893 ? S 0:00 /usr/lib/gvfs/gvfsd-metadata
1896 ? S 0:00 /usr/lib/gnome-disk-utility/gdu-notification-daemon
1900 ? Ssl 0:00 /usr/lib/bonobo-activation/bonobo-activation-server --ac-activate --ior-output-fd=19
1906 ? S 0:00 python /usr/share/system-config-printer/applet.py
1908 ? Sl 0:00 /usr/lib/evolution/2.28/evolution-alarm-notify
1920 ? S 0:05 /usr/lib/gnome-panel/clock-applet --oaf-activate-iid=OAFIID:GNOME_ClockApplet_Factory --oaf-ior-fd=20
1970 ? S 0:52 /usr/lib/gnome-panel/wnck-applet --oaf-activate-iid=OAFIID:GNOME_Wncklet_Factory --oaf-ior-fd=21
1977 ? S 0:04 /usr/lib/gnome-applets/trashapplet --oaf-activate-iid=OAFIID:GNOME_Panel_TrashApplet_Factory --oaf-ior-fd=22
2030 ? S 0:00 /usr/lib/gnome-panel/notification-area-applet --oaf-activate-iid=OAFIID:GNOME_NotificationAreaApplet_Factory --oaf-ior-fd=24
2039 ? S 0:07 /usr/lib/notify-osd/notify-osd
2090 ? Sl 1:37 gnome-terminal
2091 ? S 0:00 gnome-pty-helper
2160 ? S 0:00 /usr/lib/gvfs/gvfsd-computer --spawner :1.6 /org/gtk/gvfs/exec_spaw/2
2194 ? S< 0:00 udevd --daemon
2195 ? S 0:00 [bluetooth]
2213 ? S< 0:00 [krfcommd]
18642 pts/1 Ss+ 0:00 bash
20791 pts/0 Ss+ 0:00 bash
30574 ? S 0:00 /sbin/dhclient -d -sf /usr/lib/NetworkManager/nm-dhcp-client.action -pf /var/run/dhclient-eth2.pid -lf /var/lib/dhcp3/dhclient-fed0d93f-d7c1-
30846 ? S 0:00 [flush-8:0]
31249 pts/2 Ss 0:00 bash
31260 pts/2 R+ 0:00 ps ax
root@ubuntu:~/resource/shell-study/0618-2013# ps ax | grep "xterm" | awk '{print $1}'
31262
root@ubuntu:~/resource/shell-study/0618-2013#
继续实例:使用xargs分析单词出现的频率
#!/bin/bash
# 分析一个文本文件中单词出现的频率.
# 使用 'xargs' 将文本行分解为单词.
# 检查命令行上输入的文件.
ARGS=1
E_BADARGS=65
E_NOFILE=66
if [ $# -ne "$ARGS" ]
# 纠正传递到脚本中的参数个数?
then
echo "Usage: `basename $0` filename"
exit $E_BADARGS
fi
if [ ! -f "$1" ] # 检查文件是否存在.
then
echo "File \"$1\" does not exist."
exit $E_NOFILE
fi
#####################################################################
cat "$1" | xargs -n1 | \
# 列出文件, 每行一个单词.
tr A-Z a-z | \
# 将字符转换为小写.
sed -e 's/\.//g' -e 's/\,//g' -e 's/ /\
/g' | \
# 过滤掉句号和逗号,
#+ 并且将单词间的空格修改为换行,
sort | uniq -c | sort -nr
# 最后统计出现次数, 把数字显示在第一列, 然后显示单词, 并按数字排序.
#####################################################################
exit 0
结果:
root@ubuntu:~/resource/shell-study/0618-2013# chmod +x test5.sh
root@ubuntu:~/resource/shell-study/0618-2013# ls
file1 logfile test1.sh test2.sh test3.sh test4.sh test5.sh
root@ubuntu:~/resource/shell-study/0618-2013# ./test5.sh test1.sh
xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option
2 then
2 if
2 echo
2 #
2 ]
2 [
1 这就非常有用了
1 比如
1 文件名参数必须被传递到脚本中
1 或
1 当文件名以一个非法字符开头的时候
1 usage:
1 not
1 filename
1 file
1 fi
1 exit
1 e_wrongargs=70
1 $e_wrongargs
1 e_file_not_exist=71
1 e_changed_mind=72
1 does
1 #!/bin/bash
1 `basename
1 argcount=1
1 $argcount
1 \$1"
1 $1
1 $0`
1 #+
1 $#
1 ?
1 !
1 -
1
root@ubuntu:~/resource/shell-study/0618-2013#
expr
通用求值表达式: 通过给定的操作(参数必须以空格分开)连接参数, 并对参数求值. 可以使算术操作, 比较操作, 字符串操作或者是逻辑操作.
expr 3 + 5
返回8
expr 5 % 3
返回2
expr 1 / 0
返回错误消息, expr: division by zero
不允许非法的算术操作.
expr 5 \* 3
返回15
在算术表达式expr中使用乘法操作时, 乘法符号必须被转义.
y=`expr $y + 1`
增加变量的值, 与let y=y+1和y=$(($y+1))的效果相同. 这是使用算术表达式的一个例子.
z=`expr substr $string $position $length`
在位置$position上提取$length长度的子串.
#!/bin/bash
# 展示一些使用'expr'的例子
# ========================
echo
# 算术 操作
# ---- ----
echo "Arithmetic Operators"
echo
a=`expr 5 + 3`
echo "5 + 3 = $a"
a=`expr $a + 1`
echo
echo "a + 1 = $a"
echo "(incrementing a variable)"
a=`expr 5 % 3`
# 取模操作
echo
echo "5 mod 3 = $a"
echo
echo
# 逻辑 操作
# ---- ----
# true返回1, false返回0,
#+ 而Bash的使用惯例则相反.
echo "Logical Operators"
echo
x=24
y=25
b=`expr $x = $y` # 测试相等.
echo "b = $b" # 0 ( $x -ne $y )
echo
a=3
b=`expr $a \> 10`
echo "If a > 10, b = 0 (false)"
echo "b = $b" # 0 ( 3 ! -gt 10 )
echo
b=`expr $a \< 10`
echo "If a < 10, b = 1 (true)"
echo "b = $b" # 1 ( 3 -lt 10 )
echo
# 注意转义操作.
b=`expr $a \<= 3`
echo "If a <= 3, b = 1 (true)"
echo "b = $b" # 1 ( 3 -le 3 )
# 也有 "\>=" 操作 (大于等于).
echo
echo
# 字符串 操作
# ------ ----
echo "String Operators"
echo
a=1234zipper43231
echo "The string being operated upon is \"$a\"."
# 长度: 字符串长度
b=`expr length $a`
echo "Length of \"$a\" is $b."
# 索引: 从字符串的开头查找匹配的子串,
# 并取得第一个匹配子串的位置.
b=`expr index $a 23`
echo "Numerical position of first \"2\" in \"$a\" is \"$b\"."
# substr: 从指定位置提取指定长度的字串.
b=`expr substr $a 2 6`
echo "Substring of \"$a\", starting at position 2,\
and 6 chars long is \"$b\"."
# 'match' 操作的默认行为就是从字符串的开始进行搜索,
#+ 并匹配第一个匹配的字符串.
#
# 使用正则表达式
b=`expr match "$a" '[0-9]*'` # 数字的个数.
echo Number of digits at the beginning of \"$a\" is $b.
b=`expr match "$a" '\([0-9]*\)'` # 注意, 需要转义括号
# == == + 这样才能触发子串的匹配.
echo "The digits at the beginning of \"$a\" are \"$b\"."
echo
exit 0
结果:
root@ubuntu:~/resource/shell-study/0618-2013# ./test6.sh
Arithmetic Operators
5 + 3 = 8
a + 1 = 9
(incrementing a variable)
5 mod 3 = 2
Logical Operators
b = 0
If a > 10, b = 0 (false)
b = 0
If a < 10, b = 1 (true)
b = 1
If a <= 3, b = 1 (true)
b = 1
String Operators
The string being operated upon is "1234zipper43231".
Length of "1234zipper43231" is 15.
Numerical position of first "2" in "1234zipper43231" is "2".
Substring of "1234zipper43231", starting at position 2,and 6 chars long is "234zip".
Number of digits at the beginning of "1234zipper43231" is 4.
The digits at the beginning of "1234zipper43231" are "1234".
root@ubuntu:~/resource/shell-study/0618-2013#
继续实例:
#!/bin/bash
echo
echo "String operations using \"expr \$string : \" construct"
echo "==================================================="
echo
a=1234zipper5FLIPPER43231
echo "The string being operated upon is \"`expr "$a" : '\(.*\)'`\"."
# 转义括号对的操作. == ==
# ***************************
#+ 转义括号对
#+ 用来匹配一个子串
# ***************************
# 如果不转义括号的话...
#+ 那么'expr'将把string操作转换为一个整数.
echo "Length of \"$a\" is `expr "$a" : '.*'`." # 字符串长度
echo "Number of digits at the beginning of \"$a\" is `expr "$a" : '[0-9]*'`."
# ------------------------------------------------------------------------- #
echo
echo "The digits at the beginning of \"$a\" are `expr "$a" : '\([0-9]*\)'`."
# == ==
echo "The first 7 characters of \"$a\" are `expr "$a" : '\(.......\)'`."
# ===== == ==
# 再来一个, 转义括号对强制一个子串匹配.
#
echo "The last 7 characters of \"$a\" are `expr "$a" : '.*\(.......\)'`."
# ==== 字符串操作的结尾 ^^
# (最后这个模式的意思是忽略前边的任何字符,直到最后7个字符,
#+ 最后7个点就是需要匹配的任意7个字符的字串)
echo
exit 0
结果:
root@ubuntu:~/resource/shell-study/0618-2013# chmod +x test7.sh
root@ubuntu:~/resource/shell-study/0618-2013# ./test7.sh
String operations using "expr $string : " construct
===================================================
The string being operated upon is "1234zipper5FLIPPER43231".
Length of "1234zipper5FLIPPER43231" is 23.
Number of digits at the beginning of "1234zipper5FLIPPER43231" is 4.
The digits at the beginning of "1234zipper5FLIPPER43231" are 1234.
The first 7 characters of "1234zipper5FLIPPER43231" are 1234zip.
The last 7 characters of "1234zipper5FLIPPER43231" are ER43231.
root@ubuntu:~/resource/shell-study/0618-2013#
先到这里了,O(∩_∩)O~
我的专栏地址:http://blog.csdn.net/column/details/shell-daily-study.html
待续。。。。。