本篇文章记录工作中比较实用,能减轻工作量的bash命令。
假设有这么一个变量silo=/home/liujiacai/codes/cascalog/silo,那么
${silo##/*/}=silo ${silo#/*/}=liujiacai/codes/cascalog/silo
##表示取后面字符串最长的那段;#表示取最短的那段,这两个是从前面删除的
${silo%%/*/}=/home/liujiacai/codes/cascalog/silo ${silo%%/*}= (空) ${silo%/*}=/home/liujiacai/codes/cascalog
%%和##功能相同,不过这个是从后面开始删的。第一个什么也没删除是因为silo最后一个字符为‘o’不是‘/’,所以不变
Bash Shell可以进行变量的条件替换,既只有某种条件发生时才进行替换
${FOO:-word}
当没有FOO变量时,返回word
${FOO:=word}
当没有FOO变量时,返回word,并且把word赋值给FOO变量
${FOO:+word}
当定义了FOO变量时,返回word
${FOO:?msg}
当没有FOO变量时,把msg送到标准错误输出
${FOO:offset:length}
length可以为空
${#FOO}
变量FOO字符个数
${FOO/pattern/string}
字符串替换,最短原则
${FOO//pattern/string}
字符串替换,最长原则
如果FOO=aabbbbbbbcc,那么
echo ${FOO//bb/dd}返回aaddddddbcc
echo ${FOO//bb/dd}返回aaddbbbbbcc
以前在做java开发时也无数次遇到RE(regex expression),每次看我都以为我懂了,直到今天我才算是明白,我掌握的知识永远是那么冰山一角。扯蛋完毕。
Warning:正则表达式和通配符(wildcard)不一样。
正则表达式分基本RE与扩展RE之分,Bash中有个命令默认只认识基本的,比如grep,但是通过-e参数就能识别扩展的了;有的可以认识扩展,这点一定要搞清楚。
在基本表达式中有这么几个特殊字符,一定要记住
RE字符 | 含义与范例 |
---|---|
^word | 待搜索的字符串(word)必须在行首 |
word$ | 待搜索的字符串(word)必须在行尾 |
. | 代表任意一个字符 |
\ | 转移符,将有特殊符号的特殊意义去掉 |
* | 重复前一个字符,一次或多次。WARN:这里和通配符中*含义不同 |
\{n,m\} | 连续n到m个的“前一个重复字符” |
[word] | []内的字符集合中任取一个字符 h[io]t 代表的是hit或者hot;其次是[0-9]、[a-z]等这种用法; 再其次是[^word],表示不含“w”、“o”、“r”、“d”中的字符 |
再说说扩展RE的特殊字符
RE字符 | 含义与范例 |
---|---|
+ | 重复前一个字符一次或一次以上,比如go+d,,可以表示god、good、goood等等 |
? | 重复前一个字符零次或一次,比如go?d,表示gd、god |
| | 表示或的意思,比如'gd|good',表示取gd或者good |
() | 分组处理字符,比如'g(la|oo)d',可以表示glad或者good |
再提醒一次,“!”叹号在正则表达式中并不是特殊字符。
Unix-like系统还存在一类字符串匹配机制--globbing,在globbing中,*和通配符的用法是一样的,代表零个或多个任意字符。git的.gitignore文件就是使用的这种字符串匹配模式
详情参见:http://en.wikipedia.org/wiki/Glob_(programming)
find path [-name] pattern 在path路径下查找名字为pattern的文件,返回基于path的相对路径
find . -type f -exec file '{}' \;这条命令查找当前目录下的文件,并且作为file命令的参数执行。{}表示当前文件名,用单引号是防止{}被shell解释器解释为shell script punctuation,分号用反斜线也是这样目的,也可以用单引号代替反斜线。
find $HOME -mtime 0查找$HOME文件夹下在24小时之内修改过的文件。这里用0是因为-mtime选项对于每个文件的修改时间取其除以24后的商,余数舍弃。
find repo/ -exec test -d {}/.svn -o -d {}/.git -o -d {}/CVS ; \ -print -prune这个命令是用来查看项目的是否有.svn与.git与CVS目录的,-o 是-or的简写,表示前面的命令为false时才执行,{}表示当前处理的文件夹名,-prun e选项可以防止不必要的嵌套查找,假设repo有如下目录结构:
repo/project1/CVS
repo/gnu/project2/.svn
repo/gnu/project3/.svn
repo/gnu/project3/src/.svn
repo/project4/.git
带上-prune选项后就不会再搜索project3/.src目录了,因为已经找到了project3/.svn了。
这个命令在管道中特别有用
find /tmp -name core -type f -print | xargs /bin/rm -f这条命令查找/tmp文件夹下名为core的文件,并且把它删除。这时的文件名中不能有空格、换行符,解决方法是加上 -0参数。
当然上面这条命令还可以这么写:
find /tmp -depth -name core -type f -delete利用find的参数-delete选项,这样比用xargs效率更高,因为这样不用再调用 fork(2) and exec(2) 来launch rm和xargs进程。
这里的-depth选项指明“先处理文件夹中的内容在处理文件夹本身”,-delete本身就暗含了-depth选项。
<span style="font-family:System;">cut -d: -f1 < /etc/passwd | sort | xargs</span>这条命令用于显示passwd文件中记录的当前系统的用户。
需要注意的时,xargs并不能一定保证,命令正确执行,有可能xargs后面的命令在接受管道前面的输入时,系统执行其他命令,改变了xargs的输入。
bash中有个test命令可以进行一系列的测试,man 一下可以看到解释为" check file types and compare values",具体语法为
test EXPRESSION其实我们最常用的是test的一个别名"[",没错,就是左方括号,语法为
[ EXPRESSION ]
如果忽略EXPRESSION,那么返回false. 常用的EXPRESSION有如下这么几个:
( EXPRESSION ) EXPRESSION is true 需要注意一点的是,括号"(",")"需要用"\"转义 ! EXPRESSION EXPRESSION is false EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true -n STRING the length of STRING is nonzero.STRING equivalent to -n STRING -z STRING the length of STRING is zero STRING1 = STRING2 the strings are equal STRING1 != STRING2 the strings are not equal INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2 INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2 INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2 INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2 INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2 INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2 FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2 FILE1 -ot FILE2 FILE1 is older than FILE2 -d FILE FILE exists and is a directory -e FILE FILE exists
test的这些Express和我们平常用的C/Java语言系列的判断不一样(比如需要对一些字符进行转义),这点让我们很不是适应,不过幸好,bash提供了补救方案,那就是"[[",使用"[["可以对文件名和字符串使用更自然的语法。可以用括号和逻辑操作符把 test 命令支持的测试组合起来。下面给出一个示例:
使用 [[ 复合命令,这里不再需要对"("与")"进行转义
[[ ( -d "$HOME" ) && ( -w "$HOME" ) ]] && echo "home is a writable directory"
参考:
http://www.ibm.com/developerworks/cn/linux/l-bash-test.html