原文出处:http://blog.csdn.net/cjsycyl/article/details/8064871
directoy=./
find ${directoy} -type d | xargs du -sh | grep ^0 | awk '{print $2}'
先在指定目录下查找 目录文件, 然后用 du -sh 计算目录大小, 找出大小为0的目录,然后打印出来即可
若是不希望循环查找下去,可以只查找本级目录:
ls -l | grep ^d | awk '{print $NF}' | xargs du -sh | grep ^0 | awk '{print $2}'
还有个比较完善的解答:
directoy=./
ls -l ${directoy} | grep ^d | awk '{printf("%s/%s\n",dir,$NF)}' dir=${directoy} | xargs du -sh | grep ^0 | awk '{print $2}'
-----------------------------------------------------------------------------------------------------------------------------------------------
由于新建的文件夹都会有一些文件自动生成,大小不一定为空,用grep ^0可能导致查询错误。
修改查询条件
directoy=./ find ${directoy} -type l | awk '{printf("%s/%s\n",dir,$NF)}' dir=${directoy} | xargs du -sh
Linux中find常见用法示例
·find path -option [ -print ] [ -exec -ok command ] {} \;
find命令的参数;
pathname: find命令所查找的目录路径。例如用.来表示当前目录,用/来表示系统根目录。
-print: find命令将匹配的文件输出到标准输出。
-exec: find命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为'command' { } \;,注意{ }和\;之间的空格。
-ok: 和-exec的作用相同,只不过以一种更为安全的模式来执行该参数所给出的shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。
#-exec command {} \; —–将查到的文件执行command操作,{} 和 \;之间有空格
#-ok 和-exec相同,只不过在操作前要询用户
====================================================
-name filename #查找名为filename的文件
-perm #按执行权限来查找
-user username #按文件属主来查找
-group groupname #按组来查找
-mtime -n +n #按文件更改时间来查找文件,-n指n天以内,+n指n天以前
-atime -n +n #按文件访问时间来查GIN: 0px">
-ctime -n +n #按文件创建时间来查找文件,-n指n天以内,+n指n天以前
-nouser #查无有效属主的文件,即文件的属主在/etc/passwd中不存
-newer f1 !f2 找文件,-n指n天以内,+n指n天以前
-ctime -n +n #按文件创建时间来查找文件,-n指n天以内,+n指n天以前
-nogroup #查无有效属组的文件,即文件的属组在/etc/groups中不存在
-nouser #查无有效属主的文件,即文件的属主在/etc/passwd中不存
-newer f1 !f2 #查更改时间比f1新但比f2旧的文件
-type b/d/c/p/l/f #查是块设备、目录、字符设备、管道、符号链接、普通文件
-size n[c] #查长度为n块[或n字节]的文件
-depth #使查找在进入子目录前先行查找完本目录
-fstype #查更改时间比f1新但比f2旧的文件
-type b/d/c/p/l/f #查是块设备、目录、字符设备、管道、符号链接、普通文件
-size n[c] #查长度为n块[或n字节]的文件
-depth #使查找在进入子目录前先行查找完本目录
-fstype #查位于某一类型文件系统中的文件,这些文件系统类型通常可 在/etc/fstab中找到
-mount #查文件时不跨越文件系统mount点
-follow #如果遇到符号链接文件,就跟踪链接所指的文件
-cpio %; #查位于某一类型文件系统中的文件,这些文件系统类型通常可 在/etc/fstab中找到
-mount #查文件时不跨越文件系统mount点
-follow #如果遇到符号链接文件,就跟踪链接所指的文件
-cpio #对匹配的文件使用cpio命令,将他们备份到磁带设备中
-prune #忽略某个目录
=====================================================
$find ~ -name "*.txt" -print #在$HOME中查.txt文件并显示
$find . -name "*.txt" -print
$find . -name "[A-Z]*" -print #查以大写字母开头的文件
$find /etc -name "host*" -print #查以host开头的文件
$find . -name "[a-z][a-z][0–9][0–9].txt" -print #查以两个小写字母和两个数字开头的txt文件
$find . -perm 755 -print
$find . -perm -007 -exec ls -l {} \; #查所有用户都可读写执行的文件同-perm 777
$find . -type d -print
$find . ! -type d -print
$find . -type l -print
$find . -size +1000000c -print #查长度大于1Mb的文件
$find . -size 100c -print # 查长度为100c的文件
$find . -size +10 -print #查长度超过期作废10块的文件(1块=512字节)
$cd /
$find etc home apps -depth -print | cpio -ivcdC65536 -o /dev/rmt0
$find /etc -name "passwd*" -exec grep "cnscn" {} \; #看是否存在cnscn用户
$find . -name "yao*" | xargs file
$find . -name "yao*" | xargs echo "" > /tmp/core.log
$find . -name "yao*" | xargs chmod o-w
======================================================
find -name april* 在当前目录下查找以april开始的文件
find -name april* fprint file 在当前目录下查找以april开始的文件,并把结果输出到file中
find -name ap* -o -name may* 查找以ap或may开头的文件
find /mnt -name tom.txt -ftype vfat 在/mnt下查找名称为tom.txt且文件系统类型为vfat的文件
find /mnt -name t.txt ! -ftype vfat 在/mnt下查找名称为tom.txt且文件系统类型不为vfat的文件
find /tmp -name wa* -type l 在/tmp下查找名为wa开头且类型为符号链接的文件
find /home -mtime -2 在/home下查最近两天内改动过的文件
find /home -atime -1 查1天之内被存取过的文件
find /home -mmin +60 在/home下查60分钟前改动过的文件
find /home -amin +30 查最近30分钟前被存取过的文件
find /home -newer tmp.txt 在/home下查更新时间比tmp.txt近的文件或目录
find /home -anewer tmp.txt 在/home下查存取时间比tmp.txt近的文件或目录
find /home -used -2 列出文件或目录被改动过之后,在2日内被存取过的文件或目录
find /home -user cnscn 列出/home目录内属于用户cnscn的文件或目录
find /home -uid +501 列出/home目录内用户的识别码大于501的文件或目录
find /home -group cnscn 列出/home内组为cnscn的文件或目录
find /home -gid 501 列出/home内组id为501的文件或目录
find /home -nouser 列出/home内不属于本地用户的文件或目录
find /home -nogroup 列出/home内不属于本地组的文件或目录
find /home -name tmp.txt -maxdepth 4 列出/home内的tmp.txt 查时深度最多为3层
find /home -name tmp.txt -mindepth 3 从第2层开始查
find /home -empty 查找大小为0的文件或空目录
find /home -size +512k 查大于512k的文件
find /home -size -512k 查小于512k的文件
find /home -links +2 查硬连接数大于2的文件或目录
find /home -perm 0700 查权限为700的文件或目录
find /tmp -name tmp.txt -exec cat {} \;
find /tmp -name tmp.txt -ok rm {} \;
find / -amin -10 # 查找在系统中最后10分钟访问的文件
find / -atime -2 # 查找在系统中最后48小时访问的文件
find / -empty # 查找在系统中为空的文件或者文件夹
find / -group cat # 查找在系统中属于 groupcat的文件
find / -mmin -5 # 查找在系统中最后5分钟里修改过的文件
find / -mtime -1 #查找在系统中最后24小时里修改过的文件
find / -nouser #查找在系统中属于作废用户的文件
find / -user fred #查找在系统中属于FRED这个用户的文件
foreach 函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell (/bin/sh)中的for语句,或是C-Shell(/bin/csh)中的foreach语句而构建的。它的语法是:
$(foreach <var>,<list>,<text>)
这个函数的意思是,把参数<list>;中的单词逐一取出放到参数<var>;所指定的变量中,然后再执行< text>;所包含的表达式。每一次<text>;会返回一个字符串,循环过程中,<text>;的所返回的每个字符串会 以空格分隔,最后当整个循环结束时,<text>;所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。
所以,<var>;最好是一个变量名,<list>;可以是一个表达式,而<text>;中一般会使用<var>;这个参数来依次枚举<list>;中的单词。举个例子:
names := a b c d
files := $(foreach n,$(names),$(n).o)
上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。
注意,foreach中的<var>;参数是一个临时的局部变量,foreach函数执行完后,参数<var>;的变量将不在作用,其作用域只在foreach函数当中。
写之前我们先来搞清楚为什么要学shell,学习要有目的性
shell简单、灵活、高效,特别适合处理一些系统管理方面的小问题
shell可以实现自动化管理,让系统管理员的工作变得容易、简单、高效
shell脚本可移植性好,在unix/linux系统中可灵活移植,几乎不用任何设置就能正常运行
shell脚本可轻松方便读取和修改源代码,不需要编译
掌握shell可以帮你解决一些故障问题,比如脚本引起的故障问题
掌握shell是一个中级以上系统工程师必需要会的
掌握shell是你系统管理进阶的必经之路
掌握shell是你面试更高级职位的一块敲门砖
那什么时候不使用Shell 脚本?
资源密集型的任务,尤其在需要考虑效率时(比如排序,hash 等)
需要处理大任务的数学操作,尤其是浮点运算,精确运算,或者复杂的算术运算(这种情况一般使用C++或FORTRAN 来处理)
有跨平台移植需求(一般使用C 或Java)
复杂的应用,在必须使用结构化编程的时候(需要变量的类型检查,函数原型,等等)
对于影响系统全局性的关键任务应用。
对于安全有很高要求的任务,比如你需要一个健壮的系统来防止入侵,破解,恶意破坏等等.
项目由连串的依赖的各个部分组成。
需要大规模的文件操作
需要多维数组的支持
需要数据结构的支持,比如链表或数等数据结构
需要产生或操作图形化界面 GUI
需要直接操作系统硬件
需要 I/O 或socket 接口
需要使用库或者遗留下来的老代码的接口
私人的,闭源的应用(shell 脚本把代码就放在文本文件中,全世界都能看到)
如果你的应用符合上边的任意一条,那么就考虑一下更强大的语言吧--或许是Perl,Python,
Ruby, 或者是更高层次的编译语言比如C/C++,Java.
本文写的都是bash相关,请对号入座
1.shell脚本是什么?组成有哪些?
通俗地讲,shell脚本就是写有一堆系统命令+简单的shell语法(变量、if判断、循环语句等)的一个文件,执行这文件能把所有命令一次性都执行了并实现一定的目的。所以要学好shell,必须要把系统一些常用的系统管理命令及文本操作命令(grep、sed、awk、sort、cut、tr、uniq、join等)掌握了,要能做到信手拈来,想实现什么功能就知道用什么命令才行,然后再学习下shell语法就可以了,shell语法比其它语言简单多了,你只需学习半日便可基本掌握。
2.怎么执行一个脚本?比如执行一个刚写好的脚本aa.sh
给用户一个读与执行的权限(chmod u+rx aa.sh),就可以用./aa.sh来执行脚本(这样执行是开启一个子shell来执行的)如果想在当前shell中执行脚本,只用给读的权限就行了,用bash aa.sh或者. aa.sh或者source aa.sh皆可执行, 不过这样执行,会将bash的一些特定扩展功能关闭,脚本可能因此而调用失败,所以不建议这样执行脚本。生产中都是给脚本一个执行权限直接开启一子shell来执行的。
3.脚本第一行怎么都是以#!开始的?代表什么意思?
#!(读音:sha-bang)实际是一个2字节的魔法数字,这是指定一个文件类型的特殊标记,它就代表一个可执行的脚本,后面跟一个路径名(注意:如果是有unix味道的脚本在#!后跟一空格再跟路径名),这个路径名指定了一个解释脚本中命令的程序,这个程序可以是shell、程序语言或者是任意一个通用程序如:
#!/bin/sh
#!/bin/bash
#!/usr/bin/perl
#!/usr/bin/tcl
#!/usr/awk -f
#!/bin/sed -f
弄个好玩的哈,随便找一个脚本打开将第一行改为#!/bin/rm,执行下这个脚本,看看有什么效果
???脚本怎么没了?对,这样改的效果就是脚本将自己删除什么也不做。
4.shell内部变量
$SHELL 显示当前系统用的shell
$BASH 显示bash路径
$BASH_SUBSHELL 提示当前subshell的层次
$BASH_VERSION 显示bash版本
$BASH_VERSINFO[n] 显示bash安装信息的一个6元素数组,与$BASH_VERSION 很像
$DIRSTACK 、$PWD 结果 等于dirs命令结果
$EDITOR 脚本调用的默认编辑器
$EUID “effective”用户ID号
$FUNCNAME 当前函数名字
$GROUPS 当前用户属于的组
$UID 用户ID号
$HOME 用户home目录
$HOSTNAME 系统主机名
$IFS 内部域分隔符,默认为空白(空格、tab、新行)
$LINENO 记录它所在脚本中它所在行和行号,一般用于调度
$MACHTYPE 显示系统类型,系统架构
$OLDPWD 老的工作目录
$OPTYPE 操作系统类型
$PATH 指向Bash外部命令所在位置,系统在它指向的目录下搜索命令
$PPID 父进程的进程ID
$PROMT_COMMAND 保存一个在主提示符显示之前需要执行的命令
$PS1 主提示符
$PS2 第二提示符,当需要额外输入时显示,默认为">"
$PS3 第三提示符,在一个select循环中显示
$PS4 第四提示符,当使用-x选项调用脚本时,这个提示符将出现在每行的输出前边,默认为"+"
$REPLY read命令如果没有给变量,那么输入将保存在$REPLY 中.在select 菜单中也可用,但是只
提供选择的变量的项数,而不是变量本身的值.
$SECONDS 这个脚本已经运行的时间(单位为秒).
$SHELLOPTS 保存shell允许的选项
$SHLVL shell层次
$TMOUT 如果$TMOUT 环境变量被设置为一个非零的时间值,那么在过了这个指定的时间之后,
shell提示符将会超时,这会引起一个logout.
5.预定义变量,适用所有shell,无法更改
$# 取出位置参数个数
$* 取出所有位置参数内容
$? 判断上一次命令执行结果是否正确,0代表正确,非0则不代表不正确
$$ 当前进程进程号
$! 后台运行的最后一进程号
$0 取出脚本名子
$1、$2、$3……位置参数
脚本位置参数个数如果超过9要用{}括起来,如${10}
$_ 保存之前执行的命令的最后一个参数
6.自定义变量
bash中变量无类型区分
aa=abc123 定义变量并赋值abc123
aa= 定义空变量或者清空变量aa,但变量还存在
export test="hello world" 设定环境变量test
export或者export -p 显示所有环境变量
declare / typeset 选项 变量名
declare 或 typeset 有同样的功能:指定变量属性。如果使用 declare 后面并没有接任何参数,那么 bash 就会主动的将所有的变量名称与内容通通叫出来,就好像使用 set 一样!
选项:
-a 将后面的变量定义成为数组 (array)
-i 将后面的变量定义成为整数(integer)
-x 将后面的变量变成环境变量,同export 一样,
-r 将后面的变量设定为只读 ,该变量不可被更改内容,也不能 unset
-f 列出脚本中的函数
readonly用来设置只读变量
readonly 变量名
readonly -f 函数名称
readonly -a 数组变量
变量间接引用 eval var1=\$$var2
7.shell脚本中的一些特殊字符
# 后面的内容到行尾都是注释,不会执行(第一行的#!是个例外)
注意:echo命令中被转义的#不能作为注释,在特定的参数替换结构或数字常量表达式中也不是注释
如 echo ${PATH#*:}
echo $((2#101011))
\ 转义字符
; 命令分隔符,可以用来在一行中写多个命令
;; 终止case结构中选项
, 逗号链接了一系列的算术操作,虽然里面的内容都被运行了,最后一项被返回
` 后置引用,命令替换
: 空命令等价于NOP,也可认为与true作用相同
可以充当占位符,例如
if [ ]
then : #什么都不做,引出分支
else
.................
fi
8.linux终端下的一些常用快捷键,可以加快操作速度的
Ctrl+a 移到命令行首
Ctrl+e 移到命令行尾
Ctrl+u 删除到行首的命令
Ctrl+k 删除到行尾的命令
Ctrl+a后再Ctrl+k 或者Ctrl+e后再Ctrl+u就是删除输入的全部命令
Ctrl+->/<- 向左/右移动一个单词(远程ssh终端不可用)
Ctrl+c 终止当前任务
Ctrl+d 登出shell
Ctrl+b 光标后退
Ctrl+h 删除光标前的字符
Ctrl+w 删除光标前的一个单词
Ctrl+j 新起一行进行输入
Ctrl+l 相当于clear,清屏
Ctrl+z 终止前台工作
Ctrl+v 插入控制字符
Ctrl+s 挂起命令执行
Ctrl+q 继续命令执行
Esc+. 重新调用前一个命令中的参数,非常有用!
9.if判断都有哪些格式?
格式一:
if [ ];then
........
fi
等价于
if [ ]
then
...........
fi
格式二:
if [ ]
then
..........
else
..........
if
格式三:
if [ ]
then
......
elif [ ]
then
.......
fi
格式四:
if [ ]
then
......
elif [ ]
then
.......
elif [ ]
then
.......
elif [ ]
........
elif
.......
fi
if-grep结构:
if grep -q aa book.txt
then echo "book.txt至少有一个字符串aa"
fi
10.if判断有哪些参数?
-b 当文件存在并且是块文件时返回真
-c 当文件存在并且是字符文件时返回真
-d 当目录存在时返回真
-e 当文件或目录存在时返回真
-f 当文件存在并且是正规文件(不是目录或者设备文件)时返回真
-g 当文件或目录存在并且设置了SGID位时返回为真
-h 当文件存在并且是符号链接文件时返回真,该选项在一些老系统上无效
-k 当文件或目录存在并且设置了“粘滞”位时返回真
-L 当文件是个符号链接返回真
-N 当从文件最后被阅读到现在被修改过时返回真
-O 当文件或目录存在并且被子当前进程的有效用户ID所指定的用户拥有时返回真。
-p 当文件存在并且是命令管道时返回为真
-r 当文件或目录存在并且可读时返回为真
-s 当文件大小大于0时返回真
-S 当文件是个socket时返回真
-t 关联到一个终端设备的文件描述符这个选项一般都用来检测是否在一个给定脚本中的 stdin[-t0]或[-t1]是一个终 端
-u 当文件或目录存在并且设置了SUID位时返回真
-w 当文件或目录存在并且可写时返回真。
-x 当文件或目录存在并且可执行时返回真。一个目录为了它的内容被访问必然是可执行的。
-z 变量是空串时返回真
-n 变量是非空串时返回真
比较字符写法:
-eq 等于
-ne 不等于
-gt 大于
-lt 小于
-le 小于等于
-ge 大于等于
= 两个字符相等
!= 两个字符不等
11.case结构:
case 变量 in
"变量值1")
..................
;;
"变量值2")
...............
;;
*)
................
;;
esac
12.循环结构:
(1)while循环
while [ ]
do
..........
done
或者while [ ];do
........
done
例:一个简单的死循环
while true
do
echo "hello"
done
(2)for循环
for 变量 in 取值列表 //取值列表可以是如1 2 3 4 5或者{1..5}或者`seq 5`或者`命令`形式
do
..........
done
(3)until循环
until [ ]
do
........
done
13.()中写命令与{}中写命令有什么区别?
()中命令执行时会开启一个新的shell,{}中的命令执行时不能正常开启一个新的shell,管道中的{}例外
14.[ ]与[[ ]]条件测试有什么区别?
[ ]是shell内建的测试命令,[[ ]]是由外置命令/usr/bin/test进行测试,[[]]结构比Bash 的[]更加灵活,在[[]]结构中,将没有文件扩展或者是单词分离,但是会发生参数扩展和命令替换.:使用[[]],而不是[],能够阻止脚本中的许多逻辑错误.比如,尽管在[]中将给出一个错误,但是&&,||,<>操作还是能够工作在一个[[]]test 之中.
15.实现标准错误伴随标准输出做转向
命令 &>/dev/null
命令 >/dev/null 2>&1
命令 >&/dev/null
16.双引号" "中的引用叫部分引用,里面内容会发生变量替换,单引号' '中的引用叫全引用,不会发生变量替换双引号阻止了所有里面的特殊字符的重新解释,但是$ ` \除外,使用双引号可以防止单词分隔
17.如何将一命令执行结果赋值给一变量?
aa=`命令`
aa=$(命令)
18.怎么清空一文件aa.txt?
>aa.txt
:>aa.txt #只适用于正规文件,不适用于管道,符号链接和某些特殊文件
cat /dev/null >aa.txt
19.echo $'\042' 打印8进制字符
echo $'\x22' 打印16进制字符
echo -e 输出转义字符
echo -e 输出转义字符
echo -e "\n" 换行
\c 最后不加上换行符
\r 回行首
\t 水平TAB
\v 垂直TAB
\' 单引号
\" 双引号
\\ 斜线\
\0 后接八进制数字,显示对应的ASCII字符
echo -e "\033[40;35mHello,world\033[0m" 显示黑底紫色字体Hello,world
背景颜色范围:40 41 42 43 44 45 46 47 48 49
字体颜色范围:30 31 32 33 34 35 36 37 38 39
黑 红 绿 黄 蓝 紫 深绿 白
20.字符串操作
${变量-默认值} 如果变量不存在传回默认值
${变量:-默认值} 如果变量不存在或值为空传回默认值
${变量=默认值} 如果变量不存在传回默认值
${变量:=默认值} 如果变量不存在或值为空传回默认值
${变量+修改值} 如果变量存在传回修改值
${变量:+修改值} 如果变量存在且值不为空传回修改值
${变量?提示信息} 如果变量不存则显示提示信息并停止执行脚本
${变量:?提示信息} 如果变量不存在或值为空则显示提示信息并停止执行脚本
注:字符串中位置编号01234……,下面的样式指正则表达式
${#变量} 显示变量字符串长度
expr length "字符串" 显示字符串长度
expr "字符串" : '样式' 显示正则表达式匹配的子串长度
expr match "字符串" '样式' 显示正则表达式匹配的子串长度
expr index "字符串" 子串 显示子串中最小字符在字符串中的位置
expr substr "字符串" 起始位置 长度 显示起始位置开始的指定长度的子串
${变量:位置起点} 由指定的位置开始,截取到字符串结束
${变量:位置起点:长度} 由指定的位置开始,截取指定长度的子字符串
${@:起点} 由起点开始,取得后面所有的位置参数 //@换成*号效果相同
${@:起点:个数} 由起点开始,取得指定个数的位置参数
${变量#样式} 由最左边开始对比变量值,删除“最短符合的字符串”
${变量##样式} 由最左边开始对比变量值,删除“最长符合的字符串”
${变量%样式} 由最右边开始对比变量值,删除“最短符合的字符串”
${变量%%样式} 由最右边开始对比变量值,删除“最长符合的字符串”
${变量/样式/替换字符串} 替换第一个对比符合的字符串
${变量//样式/替换字符串} 替换全部对比符合的字符串
${变量/#样式/替换字符串} 替换第一个对比符合的字符串,样式要出现在变量值开头
${变量/样式/} 删除第一个对比符合的字符串
${变量//样式/} 删除全部对比符合的字符串
${变量/#样式/} 删除第一个对比符合的字符串,样式要出现在变量值开头
${变量/%样式/} 删除第一个对比符合的字符串,样式要出现在变量值结尾
${!开头字符串@}或
${!开头字符串*} 把所有以指定字符串开头的变量名称列出,各变量间用$IFS定义的第一个分隔符(通常是空格)隔开
${!数组变量[@]}或
${!数组变量[*]} 把数组变量所有索引列出,各索引值间用$IFS定义的第一个分隔符(通常是空格)隔开
21.help 显示所有bash内置命令,用“help 命令”无结果的说明这个命令不是内置命令
22.set 显示shell所有内部变量和函数
set -o 查看shell所有属性的开关状态
set -o emacs 打开emacs模式
set +o emacs 关闭emacs模式(不能用上下键查找历史命令)
set -C 保护已存在的文件,避免转向输出时被覆盖掉文件的内容 同set -o noclobber
set -c 恢复正常
set -v 将脚本执行的每一进程程序代码显示出来,一般用于shell排错
set -x 将执行跟踪功能打开
set +x 关闭跟踪执行功能
unset -v 变量名称 取消变量
unset -f 函数名称 取消函数
23.shopt 显示shell行为模式各选项开关状态
shopt -s 启用选项
shopt -u 关闭选项
shopt -o 同set -o
shopt -s -o nounset 强制变量一定要经过声明才能使用
24.多行注释方法
:<<END
第一行批注
第二行批注
第三行批注
……
END
25.正则表达式
\b是正则表达式规定的一个元字符,代表着单词的开头或结尾,也就是单词的分界处。如果要精确地查找hi这个单词的话,我们应该使用\bhi\b。
.是另一个元字符,匹配除了换行符以外的任意字符。
*同样是元字符,不过它代表的不是字符,也不是位置,而是数量——它指定*前边的内容可以连续重复使用任意次以使整个表达式得到匹配。因此,.*连在一起就意味着任意数量的不包含换行的字符。
+ 匹配重复1次或更多次
? 匹配重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
\d匹配一位数字 0\d\d-\d\d\d\d\d\d\d\d 等同于 0\d{2}-\d{8}
\s匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等。
\w匹配字母或数字或下划线或汉字等。
^ 匹配字符串的开始
$ 匹配字符串的结束
[0-9]代表的含意与\d就是完全一致的
[a-z0-9A-Z_]也完全等同于\w
(\d{1,3}\.){3}\d{1,3}是一个简单的IP地址匹配表达式
POSIX 字符类. [:class:]
这是另外一个可选的用于指定匹配字符范围的方法.
[:alnum:] 匹配字母和数字.等同于A-Za-z0-9.
[:alpha:] 匹配字母. 等同于A-Za-z.
[:blank:] 匹配一个空格或是一个制表符(tab).
[:cntrl:] 匹配控制字符.
[:digit:] 匹配(十进制)数字. 等同于0-9.
[:graph:] (可打印的图形字符). 匹配 ASCII 码值的33 - 126 之间的字符. 这和下面提到的
[:print:]一样,但是不包括空格字符.
[:lower:] 匹配小写字母. 等同于a-z.
[:print:] (可打印字符). 匹配 ASCII 码值 32 - 126 之间的字符. 这和上面提到的一样
[:graph:],但是增多一个空格字符.
[:space:] 匹配空白字符 (空格符和水平制表符).
[:upper:] 匹配大写字母. 等同于A-Z.
[:xdigit:] 匹配十六进制数字. 等同于0-9A-Fa-f.
注意: POSIX 字符类一般都要求用引号或是双方括号[[ ]]引起来.
26.算术扩展
$((算术式))
expr 算术式
$[算术式]
declare -i 变量=算术式
let 算术式
27.read 由标准输入读取一行数据
用例1:
echo "请输入你的名字"
read yname
echo "你的名字是:$yname"
用例2:
read -p '请输入你的英文名字:'
echo '你的名字是:' $REPLY
用例3:
read -p "请输入你的英文名字: " -t 30 name
echo "你的名字是: $name"
用例4:
read LINE <data 将data的第一行放入变量LINE中
用例5:
read f1 f2 f3 f4 <data 如果data中数据行以空格分隔,用此读取各字段值
用例6:
IFS=':'
read f1 f2 f3 f4 f5 f6 f7 </etc/passwd 读取passwd中的7个域值
read -r 不过滤转义字符
28.数组定义
(1) name=(value0 value1 ... valuen)
(2) name[0]=value0
name[1]=value1
...
name[n]=valuen
清除数组
unset aa
aa=
echo ${aa[@]} 或者echo ${aa[*]} 显示数组aa所有元素
echo ${#aa[@]} 或者echo ${#aa[*]} 显示数组aa元素个数
echo ${aa[@]:3}或者echo ${aa[*]:3} 显示数组aa中3个以后的所有元素
echo ${aa[@]:3:2} 显示数组aa中3个以后的2个元素
echo ${#aa[3]} 显示数组aa中第4个元素长度
aa=( one two three four five five )
从字符串的前部删除最短的匹配,匹配字串是一个正则表达式.
echo ${aa[@]#f*r} # one two three five five
# 匹配表达式作用于数组所有元素.
# 匹配了"four"并把它删除.
字符串前部最长的匹配
echo ${aa[@]##t*e} # one two four five five
# 匹配表达式作用于数组所有元素.
# 匹配"three"并把它删除.
字符串尾部的最短匹配
echo ${aa[@]%h*e} # one two t four five five
# 匹配表达式作用于数组所有元素.
# 匹配"hree"并把它删除.
字符串尾部的最长匹配
echo ${aa[@]%%t*e} # one two four five five
# 匹配表达式作用于数组所有元素.
# 匹配"three"并把它删除.
第一个匹配的子串会被替换
echo ${aa[@]/fiv/XYZ} # one two three four XYZe XYZe
#匹配表达式作用于数组所有元素.
所有匹配的子串会被替换
echo ${aa[@]//iv/YY} # one two three four fYYe fYYe
# 匹配表达式作用于数组所有元素.
删除所有的匹配子串,没有指定代替字串意味着删除
echo ${aa[@]//fi/} # one two three four ve ve
# 匹配表达式作用于数组所有元素.
替换最前部出现的字串
echo ${aa[@]/#fi/XY} # one two three four XYve XYve
# 匹配表达式作用于数组所有元素.
替换最后部出现的字串
echo ${aa[@]/%ve/ZZ} # one two three four fiZZ fiZZ
# 匹配表达式作用于数组所有元素.
复制一个数组.
array2=( "${array1[@]}" ) 或 array2="${array1[@]}"
给数组增加一个元素.
array=( "${array[@]}" "new element" ) 或 array[${#array[*]}]="new element"
如果数组存放的是变量,显示数组中变量内容方法:
echo ${!aa[0]}
eval echo $(echo \$${aa[0]})
eval echo \$${aa[0]}
29.bash 执行命令的优先级:
1.别名
2.关键字
3.函数
4.内置命令
5.脚本或可执行程序($PATH)
30.文件代码
fd<>文件 开启文件并指定文件代码为fd
exec 6<>文件 开启文件并指定文件代码为6
fd<&- 关闭文件代码fd
exec 6<&- 关闭文件代码6
n<&m 复制转向输入的文件文件代码m,存成n,使n连接至m
n>&m 复制转向输出的文件文件代码m,存成n,使n连接至m
本文出自 “老林的技术笔记” 博客,请务必保留此出处http://lilinqing.blog.51cto.com/1122687/487749
在Makefile中我们经常看到 = := ?= +=这几个赋值运算符,那么他们有什么区别呢?我们来做个简单的实验
新建一个Makefile,内容为:
ifdef DEFINE_VRE
VRE = “Hello World!”
else
endif
ifeq ($(OPT),define)
VRE ?= “Hello World! First!”
endif
ifeq ($(OPT),add)
VRE += “Kelly!”
endif
ifeq ($(OPT),recover)
VRE := “Hello World! Again!”
endif
all:
@echo $(VRE)
敲入以下make命令:
make DEFINE_VRE=true OPT=define 输出:Hello World!
make DEFINE_VRE=true OPT=add 输出:Hello World! Kelly!
make DEFINE_VRE=true OPT=recover 输出:Hello World! Again!
make DEFINE_VRE= OPT=define 输出:Hello World! First!
make DEFINE_VRE= OPT=add 输出:Kelly!
make DEFINE_VRE= OPT=recover 输出:Hello World! Again!
从上面的结果中我们可以清楚的看到他们的区别了
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
之前一直纠结makefile中“=”和“:=”的区别到底有什么区别,因为给变量赋值时,两个符号都在使用。网上搜了一下,有人给出了解答,但是本人愚钝,看不懂什么意思。几寻无果之下,也就放下了。今天看一篇博客,无意中发现作者对于这个问题做了很好的解答。解决问题之余不免感叹,有时候给个例子不就清楚了吗?为什么非要说得那么学术呢。^_^
1、“=”
make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:
x = foo
y = $(x) bar
x = xyz
在上例中,y的值将会是 xyz bar ,而不是 foo bar 。
2、“:=”
“:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
x := foo
y := $(x) bar
x := xyz
在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。
所有的自动化变量及其说明:
$@
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$%
仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
$<
依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$?
所有比目标新的依赖目标的集合。以空格分隔。
$^
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$+
这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
Linux shell用法和技巧
使用Linux shell是我每天的基本工作,但我经常会忘记一些有用的shell命令和l技巧。当然,命令我能记住,但我不敢说能记得如何用它执行某个特定任务。于是,我开始在一个文本文件里记录这些用法,并放在我的Dropbox里,现在,向大家分享这个文件。这个文件我会不断的更新。需要注意一点的是,有些用法需要在你的Linux系统里安装额外的软件。
UPDATE: November 25, 2013
检查远程端口是否对bash开放:
echo >/dev/tcp/8.8.8.8/53 && echo "open"
让进程转入后台:
Ctrl + z
将进程转到前台:
fg
产生随机的十六进制数,其中n是字符数:
openssl rand -hex n
在当前shell里执行一个文件里的命令:
source /home/user/file.name
截取前5个字符:
${variable:0:5}
SSH debug 模式:
ssh -vvv user@ip_address
SSH with pem key:
ssh user@ip_address -i key.pem
用wget抓取完整的网站目录结构,存放到本地目录中:
wget -r --no-parent --reject "index.html*" http://hostname/ -P /home/user/dirs
一次创建多个目录:
mkdir -p /home/user/{test,test1,test2}
列出包括子进程的进程树:
ps axwef
创建 war 文件:
jar -cvf name.war file
测试硬盘写入速度:
dd if=/dev/zero of=/tmp/output.img bs=8k count=256k; rm -rf /tmp/output.img
测试硬盘读取速度:
hdparm -Tt /dev/sda
获取文本的md5 hash:
echo -n "text" | md5sum
检查xml格式:
xmllint --noout file.xml
将tar.gz提取到新目录里:
tar zxvf package.tar.gz -C new_dir
使用curl获取HTTP头信息:
curl -I http://www.example.com
修改文件或目录的时间戳(YYMMDDhhmm):
touch -t 0712250000 file
用wget命令执行ftp下载:
wget -m ftp://username:password@hostname
生成随机密码(例子里是16个字符长):
LANG=c < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-16};echo;
快速备份一个文件:
cp some_file_name{,.bkp}
访问Windows共享目录:
smbclient -U "DOMAIN\user" //dc.domain.com/share/test/dir
执行历史记录里的命令(这里是第100行):
!100
解压:
unzip package_name.zip -d dir_name
输入多行文字(CTRL + d 退出):
cat > test.txt
创建空文件或清空一个现有文件:
> test.txt
与Ubuntu NTP server同步时间:
ntpdate ntp.ubuntu.com
用netstat显示所有tcp4监听端口:
netstat -lnt4 | awk '{print $4}' | cut -f2 -d: | grep -o '[0-9]*'
qcow2镜像文件转换:
qemu-img convert -f qcow2 -O raw precise-server-cloudimg-amd64-disk1.img \ precise-server-cloudimg-amd64-disk1.raw
重复运行文件,显示其输出(缺省是2秒一次):
watch ps -ef
所有用户列表:
getent passwd
Mount root in read/write mode:
mount -o remount,rw /
挂载一个目录(这是不能使用链接的情况):
mount --bind /source /destination
动态更新DNS server:
nsupdate < <EOF update add $HOST 86400 A $IP send EOF
递归grep所有目录:
grep -r "some_text" /path/to/dir
列出前10个最大的文件:
lsof / | awk '{ if($7 > 1048576) print $7/1048576 "MB "$9 }' | sort -n -u | tail
显示剩余内存(MB):
free -m | grep cache | awk '/[0-9]/{ print $4" MB" }'
打开Vim并跳到文件末:
vim + some_file_name
Git 克隆指定分支(master):
git clone git@github.com:name/app.git -b master
Git 切换到其它分支(develop):
git checkout develop
Git 删除分支(myfeature):
git branch -d myfeature
Git 删除远程分支
git push origin :branchName
Git 将新分支推送到远程服务器:
git push -u origin mynewfeature
打印历史记录中最后一次cat命令:
!cat:p
运行历史记录里最后一次cat命令:
!cat
找出/home/user下所有空子目录:
find /home/user -maxdepth 1 -type d -empty
获取test.txt文件中第50-60行内容:
< test.txt sed -n '50,60p'
运行最后一个命令(如果最后一个命令是mkdir /root/test, 下面将会运行: sudo mkdir /root/test):
sudo !!
创建临时RAM文件系统 – ramdisk (先创建/tmpram目录):
mount -t tmpfs tmpfs /tmpram -o size=512m
Grep whole words:
grep -w "name" test.txt
在需要提升权限的情况下往一个文件里追加文本:
echo "some text" | sudo tee -a /path/file
列出所有kill signal参数:
kill -l
在bash历史记录里禁止记录最后一次会话:
kill -9 $$
扫描网络寻找开放的端口:
nmap -p 8081 172.20.0.0/16
设置git email:
git config --global user.email "me@example.com"
To sync with master if you have unpublished commits:
git pull --rebase origin master
将所有文件名中含有”txt”的文件移入/home/user目录:
find -iname "*txt*" -exec mv -v {} /home/user \;
将文件按行并列显示:
paste test.txt test1.txt
shell里的进度条:
pv data.log
使用netcat将数据发送到Graphite server:
echo "hosts.sampleHost 10 `date +%s`" | nc 192.168.200.2 3000
将tabs转换成空格:
expand test.txt > test1.txt
Skip bash history:
< space >cmd
去之前的工作目录:
cd -
拆分大体积的tar.gz文件(每个100MB),然后合并回去:
split –b 100m /path/to/large/archive /path/to/output/files cat files* > archive
使用curl获取HTTP status code:
curl -sL -w "%{http_code}\\n" www.example.com -o /dev/null
设置root密码,强化MySQL安全安装:
/usr/bin/mysql_secure_installation
当Ctrl + c不好使时:
Ctrl + \
获取文件owner:
stat -c %U file.txt
block设备列表:
lsblk -f
找出文件名结尾有空格的文件:
find . -type f -exec egrep -l " +$" {} \;
找出文件名有tab缩进符的文件
find . -type f -exec egrep -l $'\t' {} \;
用”=”打印出横线:
printf '%100s\n' | tr ' ' =