高级Bash脚本编程指南(23):复杂命令

高级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长度的子串.

一个使用expr的实例:
#!/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

待续。。。。。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值