常用shell脚本记录

1.查找特定时间修改的文件:

  
  
  
  
  1. #!/bin/sh 
  2. # Copyright by Ming Gong(宫敏) for news://news.freesoft.cei.gov.cn/chinese.com.linux 
  3. # GPL V2, Jun 30, 1998 
  4. # The right of usage, distribution and modification is here by granted by the author. 
  5. # The author deny any responsibilities and liabilities related to the code. 
  6. #Edit by deven 2012-05-31 
  7. OK=0 
  8. A=`find $1 -print` 
  9. if expr $3 == 01 >/dev/null  ; then  OK=1 ; fi 
  10. if expr $3 == 02 >/dev/null  ; then  OK=1 ; fi 
  11. if expr $3 == 03 >/dev/null  ; then  OK=1 ; fi 
  12. if expr $3 == 04 >/dev/null  ; then  OK=1 ; fi 
  13. if expr $3 == 05 >/dev/null  ; then  OK=1 ; fi 
  14. if expr $3 == 06 >/dev/null  ; then  OK=1 ; fi 
  15. if expr $3 == 07 >/dev/null  ; then  OK=1 ; fi 
  16. if expr $3 == 08 >/dev/null  ; then  OK=1 ; fi 
  17. if expr $3 == 09 >/dev/null  ; then  OK=1 ; fi 
  18. if expr $3 == 10 >/dev/null  ; then  OK=1 ; fi 
  19. if expr $3 == 11 >/dev/null  ; then  OK=1 ; fi 
  20. if expr $3 == 12 >/dev/null  ; then  OK=1 ; fi 
  21.  
  22. echo $A 
  23. exit 
  24. if expr $OK == 1 > /dev/null ; then 
  25.         ls -ld --full-time $A 2>/dev/null|grep $2| grep "$3-$4"|grep "$5"; 
  26. else 
  27.         echo Usage: $0 path Year Month Day; 
  28.         echo Example: $0 ~ 2011 06 30 11:10; 
  29. fi 

2.如何实现取出文件中特定的列内容

  
  
  
  
  1. 如果你只想看文件的前5行,可以使用head命令, 
  2. 如: head -5 /etc/passwd  
  3.  
  4. 如果你想查看文件的后10行,可以使用tail命令, 
  5. 如: tail -10 /etc/passwd  
  6.  
  7. 你知道怎么查看文件中间一段吗?你可以使用sed命令  
  8. 如: sed -n '5,10p' /etc/passwd 这样你就可以只查看文件的第5行到第10行。 

3.如何只列子目录?

  
  
  
  
  1. ls -F | grep /$ 或者 alias sub = "ls -F | grep /$"(linux) 
  2. ls -l | grep "^d" 或者 ls -lL | grep "^d" (Solaris) 

4.如何实现取出文件中特定的列内容

  
  
  
  
  1. 我们经常会遇到需要取出分字段的文件的某些特定字段,例如/etc/password就是通过“:”分隔各个字段的。可以通过cut命令来实现。例如,我们希望将系统账号名保存到特定的文件,就可以: 
  2.   cut -d: -f 1 /etc/passwd >; /tmp/users 
  3. awk -F: '{print $1}' /etc/passwd
  4.   -d用来定义分隔符,默认为tab键,-f表示需要取得哪个字段。 
  5.   当然也可以通过cut取得文件中每行中特定的几个字符,例如: 
  6.   cut -c3-5 /etc/passwd 
  7.   就是输出/etc/passwd文件中每行的第三到第五个字符。 
  8.   -c 和 -f 参数可以跟以下子参数: 
  9.   N 第N个字符或字段 
  10.   N- 从第一个字符或字段到文件结束 
  11.   N-M 从第N个到第M个字符或字段 
  12.   -M 从第一个到第N个字符或字段  
 

5.打印uid大于500的用户 awk -F: '{if ($3>=500) print $1}' /etc/passwd

6.如何查找某条命令的相关库文件 在制作自己的发行版时经常需要判断某条命令需要哪些库文件的支持,以确保指定的命令在独立的系统内可以可靠的运行。 在Linux环境下通过ldd命令即可实现,在控制台执行: ldd /bin/ls 即可得到/bin/ls命令的相关库文件列表。 

7.有些单词在一篇文章中经常会出现很多次,怎么统计这个单词的个数呢?! 如:文件kshfile,统计shell这个单词的个数,
$cat kshfile
ksh
The "Korn" shell, written by David Korn of AT&T Bell Labs (now Lucent). Written as a major upgrade to "sh", it is compatible with it, but has many more internal commands for the most frequently used functions. It also incorporates most of the same features from tcsh which enhance interactive use (command line history recall etc.). This shell is now available on most systems. It was slow to gain acceptance because earlier versions were encumbered by AT&T licensing.
$cat kshfile|tr " " "\n"|grep -wc shell

#tr " " "\n"用空格替代换行符,然后再统计行数,呵呵

用 tr 过滤文件
了解文本实用程序
Jacek Artymiak(
[email protected] )自由作家和顾问
没有人曾说过 sed 很容易 - 它确实不容易!但通过使用 tr,您可以非常容易地实现 sed 的许多最基本功能。Jacek Artymiak 向您展示如何去做。

您可以将 tr 看作为 sed 的(极其)简化的变体:它可以用一个字符来替换另一个字符,或者可以完全除去一些字符。您也可以用它来除去重复字符。这就是所有 tr 所能够做的。

那么,为什么要使用 tr,而不使用 sed 呢?当然是为了使事情简单。例如,如果我们希望用字母"z"来替换出现的所有字母"a",则可以用 tr a z,这条命令毫无疑问比 sed -e s/a/z/g 简单,尤其在把它用到脚本中时,其中的引号转义很让人头痛。另外,在使用 tr 时,可以避免写那些让人讨厌的正则表达式。

使用 tr 很简单:使用前面一段中所给出的符号表示法,用一个字符去替换出现的所有另一个字符。当需要替换多个字符时,使用类似于这样的表示法:tr abc xyz,它表示用字母"x"去替换出现的所有字母"a",用字母"y"去替换所有字母"b",用字母"z"去替换所有字母"c"。这两组中所列出的字符的 数目不必相等。

您也可以指定字符的范围。例如,tr a-z A-Z 将用对应的大写字母来替换所有的小写字母(例如,它将"no smoking"转换成"NO SMOKING")。当您在 vi 编辑器中想强调正在编辑的文本的某一部分时,使用这一特殊技巧非常方便。只要按一下 Escape 键,然后按 : 键,再输入 2,4!tr 'a-z' 'A-Z',最后按一下 Return 键。现在,从第 2 行到第 4 行的字母就都转换成了大写字母。

关于 tr 的其它内容
GNU 手册上提到,tr 在执行您所选择的操作时,通过将标准输入复制到标准输出,从而实现"转换、压缩和/或删除字符"。在这篇技巧文章中,您将了解到这些选项;当然也可以通过了解 tr 的手册页或信息页,学习到更多关于 tr 的内容。

打开一个新的终端窗口,输入 man tr 或 info tr - 或者打开一个新的浏览器窗口,并链接到 gnu.org 上的 tr 手册页(关于这个链接,请参阅参考资料)。

另外,当有人给您发送了一个在 Mac OS 或 DOS/Windows 机器上创建的文本文件时,您会发现 tr 非常有用。如果没有将文件保存为使用 UNIX 换行符来表示行结束这种格式,则需要将这样的文件转换成本机 UNIX 格式,否则一些命令实用程序不会正确地处理这些文件。Mac OS 的行尾以回车字符结束,许多文本处理工具将这样的文件作为一行来处理。为了纠正这个问题,可以用下列技巧:
Mac -> UNIX:tr '\r' '\n' < macfile > unixfile
UNIX -> Mac:tr '\n' '\r' < unixfile > macfile

Microsoft DOS/Windows 约定,文本的每行以回车字符并后跟换行符结束。为了纠正这个问题,可以使用下列命令:
DOS -> UNIX:tr -d '\r' < dosfile > unixfile
UNIX -> DOS:在这种情况下,需要用 awk,因为 tr 不能插入两个字符来替换一个字符。要使用的 awk 命令为 awk '{ print $0"\r" }' < unixfile > dosfile

另外,当您需要对文本文件做一些简单的整理工作(如用 tr -d '\t' 除去制表符,用 tr -s ' ' 除去多余的空格,或者用 tr -d '\n' 将分开的几行合成一行)时,会需要用 tr。同样,可以在 vi 内使用所有这些命令;只要记住:在 tr 命令前要加上您希望处理的行范围和感叹号(!),如 1,$!tr -d '\t'(美元符号表示最后一行)中所示。

8.#显示文件tmp的奇数行的内容:

[javalee//home/javalee/myshell]sed -n ‘1,$p;n’ tmp
aaaaaa
kasdkfkk
dfddf
asdfjklkas
#显示文件tmp的偶数行的内容:
[javalee//home/javalee/myshell]sed -n ‘1,$n;p’ tmp
dddddd
djhasdjf
kjsdfklkls

  
  
  
  
  1. n   
  2. 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令。   
  3. N   
  4. 追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。   
  5. p  
  6. 打印模板块的行。  
  7. 打印模板块的第一行 

9.技巧:倒读文本

例如文章:

$cat -n tmp
1 abcdefgh
2 123234234
3 sjdfk23423
1,
行号倒序:
$cat -n tmp|tac #taccat很有趣吧~~
3 sjdfk23423
2 123234234
1 abcdefgh
2,
每行倒读:
$cat tmp|rev
hgfedcba
432432321
32432kfdjs
3,
全部倒过来:
$cat -n tmp|rev|tac
32432kfdjs 3
432432321 2
hgfedcba 1


10.删除文件中空行的几种方法

  
  
  
  
  1. 1,cat filename|tr -s '\n' 
  2. 2,sed '/^$/d' filename 
  3. 3,awk '{if($0!="")print}' filename 
  4. 4,用grep也可以,但是比较麻烦 
11. 用输入的字符串和任意一个数字进行运算 , 可以判断 !

  
  
  
  
  1. if [ -n "`echo $1|sed -n '/^[0-9][0-9]*$/p'`" ] 
  2. then 
  3. echo " is number!" 
  4. else 
  5. echo " is not number!" 
  6. fi 
  7. 或者 
  8. echo $1|awk '{if($0~/[^0-9]/) {print "'$1' is not number"} else{print "'$1' isnumber"}}' 
if -n str1 当字符串的长度大于0时为真 


12.查找特定字符所在行行号的方法

1.grep -n "string" filename
2.sed -n '/string/=' filename
3.awk '/string/{print FNR}' filename

13.查找一个关键词在整个文件中出现的次数

代码:
awk '/keyword/{count++}END{print count }' filename

替换

代码:
awk '{gsub(/oldstr/,"newstr");print}' filename

14.说明:expr在循环中用于增量计算。先将变量初始化为0,然后循环值加1,反引号的用法为命令替代。

> LOOP=0
> LOOP=`expr $LOOP + 1`

while语句测试:
1
#!/bin/bash
m=0
while [ $m -lt 10 ]
do
    echo $m
   
m=`expr $m + 1`   #注意m旁边的空格,这里不能使用m="$m+1",好奇怪
done
2

declare -i m=0         #别一种在算术运算时声明变量的方法,-i 定义为整数integer 
while [ $m -lt 10 ]
do
       echo $m
       m=$m+1
done
until
语句测试:
1
#!/bin/bash
declare -i m=10
until [ $m -lt 10 ]
do
    echo $m
    m=$m-1
done
2

declare -i m=0
while [ $m -lt 10 ]
do
       echo $m
       m=$m+1        
done
15.
shell一句话批量修改文件后缀

  (1)  $ for file in $(ls *.png);do mv $file `echo $file | sed s/jpg$/png/g`;done

  (2) 更简单的:

    $ rename png jpg *.png

   (3) 用find更切题:

    $ find . -name "*.jpg" | while read file; do mv $file $(echo $file|sed s/jpg$/png/g); done

  当然也可以这么用:

    $ for file in $(find . -name "*.png"); do mv $file $(echo $file|sed s/png$/jpg/g); done

16.用grep、xargs 、rm查找包含某字符串的文件并删除

grep -l "abc" ./* |xargs rm -rf

删除当前目录下包含“abc”的文件

‍find命令的例子;

2、让当前目录中文件属主具有读、写权限,并且文件所属组的用户和其他用户具有读权限的文件,(Deven:注意{}之间没有空格,{}与\之前有一个空格);

$ find . -type f -perm 644 -exec ls -l {} \;

3、为了查找系统中所有文件长度为0的普通文件,并列出它们的完整路径;

$ find / -type f -size 0 -exec ls -l {} \;

4、查找/var/logs目录中更改时间在7日以前的普通文件,并在删除之前询问它们;

$ find /var/logs -type f -mtime +7 -ok rm {} \;

如果删除之前不需要询问则把-ok改为-exec就行了, find /var/log/ -type f -ctime +10 -exec rm {} \;

注意,删除之前也不会提示,请慎用: find  /var/log/ -type f -ctime +10 |xargs rm;

如果问题改为:查找/data/目录中更改时间在10日以前的普通文件,但是/data/backup/目录中所有的文件都不删除

find /data/ -type f -ctime +10|grep -v '/data/backup'|xargs rm

-exec    find命令对匹配的文件执行该参数所给出的s h e l l命令。相应命令的形式为

' command' {} \;,注意{ }\;之间的空格,exec之后可以接很多命令。

find ./ -type f -print -exec chmod o+x {} \; 

5、为了查找系统中所有属于root组的文件;

$find . -group root -exec ls -l {} \;
-rw-r--r-- 1 root     root       595 10月 31 01:09 ./fie1

6、find命令将删除当目录中访问时间在7日以来、含有数字后缀的admin.log文件。

该命令只检查三位数字,所以相应文件的后缀不要超过999。先建几个admin.log*的文件 ,才能使用下面这个命令

$ find . -name "admin.log[0-9][0-9][0-9]" -atime -7   -ok rm {} \;
< rm ... ./admin.log001 > ? n
< rm ... ./admin.log002 > ? n
< rm ... ./admin.log042 > ? n
< rm ... ./admin.log942 > ? n

7、为了查找当前文件系统中的所有目录并排序;

$ find . -type d | sort

8.删除/data/目录下10天之前的文件,但是在filelist中的文件不能删除

find /data/ -type f -ctime +10;sort filelist > tmp2.txt

comm -3 tmp.txt tmp2.txt |xargs rm
 
这样就可以删除了。。
 
在使用find命令的-exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递给exec执行。但有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。这就是xargs命令的用处所在,特别是与find命令一起使用。

find命令把匹配到的文件传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部,不像-exec选项那样。这样它可以先处理最先获取的一部分文件,然后是下一批,并如此继续下去。

在有些系统中,使用-exec选项会为处理每一个匹配到的文件而发起一个相应的进程,并非将匹配到的文件全部作为参数一次执行;这样在有些情况下就会出现进程过多,系统性能下降的问题,因而效率不高;

而使用xargs命令则只有一个进程。另外,在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。

来看看xargs命令是如何同find命令一起使用的,并给出一些例子。

在当前目录下查找所有用户具有读、写和执行权限的文件,并收回相应的写权限:

# ls -l
drwxrwxrwx 2 sam    adm       4096 10月 30 20:14 file6
-rwxrwxrwx 2 sam    adm          0 10月 31 01:01 http3.conf
-rwxrwxrwx 2 sam    adm          0 10月 31 01:01 httpd.conf

# find . -perm -7 -print | xargs chmod o-w
# ls -l
drwxrwxr-x 2 sam    adm       4096 10月 30 20:14 file6
-rwxrwxr-x 2 sam    adm          0 10月 31 01:01 http3.conf
-rwxrwxr-x 2 sam    adm          0 10月 31 01:01 httpd.conf

用grep命令在所有的普通文件中搜索hostname这个词(Deven:注意,这里是搜索文件里面的内容包好hostname,文件名是hostname无法搜出):

# find . -type f -print | xargs grep "hostname"
./httpd1.conf:#     different IP addresses or hostnames and have them handled by the
./httpd1.conf:# VirtualHost: If you want to maintain multiple domains/hostnames
on your

用grep命令在当前目录下的所有普通文件中搜索hostnames这个词:

# find . -name \* -type f -print | xargs grep "hostnames"
./httpd1.conf:#     different IP addresses or hostnames and have them handled by the
./httpd1.conf:# VirtualHost: If you want to maintain multiple domains/hostnames
on your

注意,在上面的例子中, \用来取消find命令中的*在shell中的特殊含义。

find命令配合使用exec和xargs可以使用户对所匹配到的文件执行几乎所有的命令。
 
查找1天前,2天内的文件:
 
f ind ./Day_1206*/* -mtime +0 -and -mtime -2 |xargs ls -lt|sort -k 6,7|more
 
或者: find ./Day_1206*/* -mtime +0 -and -mtime -2 -exec ls -lt {} \;|sort -k 6,7|more
 
注意: -mtime +0代表1天前,-mtime +n代表(n+1)*24小时之前
此外find ./Day_1206*/*不能写成find ./Day_1206*

9.分 割

以符号+为准,将字符分割为左右两部分

使用sed

举例:

命令 date --rfc-3339 seconds 的输出为

2007-04-14 15:09:47+08:00

取其+左边的部分

date --rfc-3339 seconds | sed 's/+[0-9][0-9]:[0-9][0-9]//g'

输出为

2007-04-14 15:09:47

取+右边的部分(Deven:

. 匹配一个非换行符的字符 如:/s.d/匹配s后接一个任意字符,然后是d。

* 匹配零或多个字符 如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行。记住,以下这样写不行。date --rfc-3339 seconds | sed 's/*+//g')

date --rfc-3339 seconds | sed 's/.*+//g'

输出为

08:00

以 空格为分割符的字符串分割

使用awk

举例:

STR_FRUIT="Banana 0.89 100"

取第3字段

echo $STR_FRUIT | awk '{ print $3;}'

Linux shell 截取字符变量的前8位,有方法如下:

expr substr “$a” 1 8

2、第二种方法:${varible:n1:n2}:截 取变量varible从n1到n2之间的字符串。

可以根据特定字符偏移和长度,使用另一种形式的变量扩展,来选择特定子字符串。试着在 bash 中输入以下行:
$ EXCLAIM=cowabunga
$ echo ${EXCLAIM:0:3}
cow
$ echo ${EXCLAIM:3:7}
abunga

这种形式的字符串截断非常简便,只需用冒号分开来指定起始字符和子字符串 长度。

三、按照指定要求分割:
比如获取后缀名
ls -al | cut -d "." -f2

10.统计deven.txt各行总和,deven.txt格式如下:

4

5

6

77

888

999

000

...
 
awk '{sum+=$0};END {print sum}' deven.txt
 
常用shell:
1.显示消耗内存/CPU最多的10个进程
ps aux | sort -nk +4 | tail
ps aux | sort -nk +3 | tail
2.日志中最后1个字段表示连接时间,求平均连接时间
tail -1000 bbs_access_20120606.log |awk 'BEGIN{sum=0;num=0;} {sum+=$NF;num++;} END{printf ("sum=%d,num=%d,avg=%f\n",sum,num,sum/num)}'
sum=189,num=1000,avg=0.189994
 

3.#对字符串进行大写转换

cat test.txt|awk '{print toupper($0)}'  

或者cat test.txt |tr '[a-z]' '[A-Z]'

或者sed y/abcdefg/ABCDEFG/ test.txt
 
二 文件内容如下:
123abc456
456def123
567abc789
789def567
要求输出:
456ABC123
123DEF456
789ABC567
567DEF789
一句话思路:以点带面,文字处理,shell不行,awk不行,用sed加正则表达式
sed -r  's/([1-9]{3})([a-f]{3})([1-9]{3})/\3\2\1/;y/abcdef/ABCDEF/'  内容文件
知识点:-r 支持扩展的正则表达式,跟grep用-P类似。y其实就是tr只是写到sed里面更好看一些,sed的查找替换,当然还有正则中的分组。sed中的分组可以这么用,awk就不行了只能用&,而且分组数量不能超过9,即不会有\10出现。
三. 文件内容如下
1.1.1.1      11
1.1.1.1      22
1.1.1.1      33
1.1.1.1      44
2.2.2.2      11
2.2.2.2      22
2.2.2.2      33
2.2.2.2      44
要求使用sed及awk分别将文件输出:
1.1.1.1       11  22  33  44
2.2.2.2       11  22  33  44
一句话思路:这个没啥思路了,上面还分析分析用什么合适,这里面没的选了,人家都说了,就弄吧。
sed   -r   'N;N;N;s/\n/ /g;s/(.*)(11 )(.*)(22 )(.*)(33 )(.*)(44)/\1\2\4\6\8/' test.txt
或者 sed 'N;N;N;s/\n/ /g;' test.txt |awk '{print $1,$2,$4,$6,$8}'
知识点:N将文件的下一行读入模式空间, 3个N就是读取下面三行进入当前模式空间,读进去的行依然保留换行,所以删除换行,后面的就不说了,你懂的。
用shell查询以“.”结尾的文件,并加上后缀“.ts”
一句话思路:在之前的曾经有过批量修改扩展名的实例,但这次有所不同,使用find命令就可以搞定
find ./ -name "*." -exec mv {} {}ts \;
或者find /data/ -name "*." -exec rename . .ts *. \;
列出最后的10万行log中请求最多前十位IP:
awk '{ip[$1]++}END{for(var in ip)print ip[var],var |"sort -nr|head -n10"}' bbs.log
或者:cat bbs.log |awk '{print $1}'|sort|uniq -c|sort -nr|head
四、可以用shell,perl等。把文件B中有的,但是文件A中没有的所有行,保存为文件C,并统计C的行数
[root@centos-5 data]# cat A
111
222
333
[root@centos-5 data]# cat B
444
555
222
333
[root@centos-5 data]# diff B A
1,2c1
< 444
< 555
---
> 111
 
diff B A | grep "<" | sed 's/< //' > C
9.把1 2 3 4 5 6按如下格式输出
1
2
3
4
5
6
sed 's/ /\n/g' test.txt 或者sed 's# #\n#g' test.txt
 
10.设计一个shell程序,在2012年12月23日凌晨3点备份并压缩前一天/svn目录的所有内容,存放在/root/bak目录里,且文件名为如下形式svn.2008.05.06.tar.gz,试写脚本。
    at 201212230300
    at> find /svn -mtime +0 -and -mtime -2 -exec cp -r {} /root/bak \;
    at> tar -czf svn.2008.05.06.tar.gz /root/bak

你可能感兴趣的:(shell,脚本,记录)