转载请注明出处: http://my.oschina.net/leejun2005/blog/60726
注:以前的1-15连载部分放在百度空间,
目前百度空间已不支持博客搜索,
但你可以使用google搜索关键词:
leejun_2005 shell学习笔记
1501.巧用bash的{}扩展备份目录: cp file.txt{,.bak} 1502.利用at执行一次性命令: echo "ls -l" | at midnight #Execute a command at a given time 1503.kill -1 或者 kill -HUP 一般用来重新读取配置文件:(一般程序自己实现的) HUP 其实就是给个信号,你的程序可以根据这个信号做一些事情,比如reload进程,或者是rotota日志。例如 squid、Nginx、xinetd。 kill就是发送一个信号,而各种信号一般都有默认的意义,但是各个软件不一样。比如ping在遇到3信号的时候就会输出统计。 nohup,就是对应的这个信号 HUP。 1504.Read-only file system:文件系统只读 如果/data在/分区上:mount -o remount /data,其实/分区也可以remount的,只是不能umount 原因:磁盘io很高、硬盘挂掉、死机等 mount -o remount,rw /data rw好像是预设值,既然有nodiratimne,加上noatime吧 1505.巧用正则的匹配位置 RSTART 和匹配长度 RLENGTH 寻找子串: $ echo 'QWADGDABCfooDGJDJLGJWLJABCbarGLDABCwhyJGKABCkkJGJKDJGLABCtnndJDK'|、 awk '{while(match($0,/ABC/)){print substr($0,RSTART);$0=substr($0,RSTART+RLENGTH)}}' 1506.多次调用 -k 实现多次排序: sort -t' ' -k3.3 -k1,1 #sort -k中的.表示按指定域中的第几个字符来排序 1507.重启网络用sudo /etc/init.d/networking restart,或者ifdown eth0 ifup eth0,注意要一起执行,否则你网络就断了。 1508.二进制文件编辑不要用vi,你保存后会在最后加换行,会破坏这个文件。vi会检查文件,如果没换行,会加上,二进制文件最后一般都没换行的。 你复制个/bin/ls,用vi打开,什么都不做,保存,wc -c看下,多一个字符。 1509.EOF 不是字符,EOF是个信号,告诉程序没了。 1510.保留相邻重复行: echo "aaa 1111 1111 1111 aaa"|awk 'a[$1]&&NR!=a[$1]+1{next}{a[$1]=NR}1' 1511.man cat出现 ^H 字符: man cat |col -b > cat-help :^H是高亮显示用的 echo 'a^Ha'|less,a就高亮了,^H是按ctrl+v,再ctrl+h输入的 BTW:为何退格出现 ^H :打字机时代,要加亮一个字符,操作方法是敲一次字符,回退,然后再重复敲一遍。(见维基百科) 1512.IFS设为换行符:IFS=$'\n' 1513.利用 find -prune 限制查找多个目录: find / \( -path /root/decli -o -path /data/robinechen -o -path /data/yunwei \) -prune -o -type f -name "*vim*" -print 1514.巧用逻辑操作打印 rm 的报错状态: rm a || echo error & rm a & ; [ $? -ne 0 ] && echo error # 实际上即使 rm a 出错,也不能打印出 error 1515.巧设RS合并行: echo "1111 33\n 5555" | awk -v RS='\\\\n\n' -v ORS="" 1 awk -v RS='\0' -F'\\\\n\n' '{for(i=1;i<=NF;i++){printf $i}}' 1516.获取进程列表及进程路径: netstat -nlp|awk -F '[ ]+|/' 'NR>2{if($0 ~/Active UNIX/){exit};res=gensub(".* +([0-9]+)/[^/]+","\\1",1,$0);a[res]}END{for(i in a){print i}}'|xargs -I {} ls -l /proc/{}|grep -E 'exe|cwd'|awk '{print}NR%2==0{print ""}' 1517.cut 也有输出分隔符: echo '1 3 5' | cut -f1-3 -d' ' --output-delimiter=o 1518.delete和backspace都无效:reset 或者 stty cooked 试试 1519.linux下创建 dvd ISO 镜像: dd if=/dev/cdrom of=~/cdimage.iso 1520.利用bash转义改变grep搜索颜色: echo $'\e'[31m; grep "$1" aaa; echo $'\e'[37m 1521.打印第2行到倒数第2行:sed '1d;$d' 1522.关于 kill -9 进程杀不掉: ps -eo stat,pid,cmd|grep httpd,看下进程状态 都D了,通常是IO导致的深度睡眠,lsof看下在干嘛, kill -9也杀不掉?恩,D和Z都是-9杀不掉的,D只能等io结束。 1523.seq -s 设置序列分隔符: seq -s, 9 #echo {1..9},|sed 's/,$\| //g' seq -s, 9 |awk '{for(i=1;i<=9;i++)print gensub(i,"null",1,$0)}' 1524.通过多次的幂运算将CPU迅速撑到 100%: while :;do echo 2^2^20|bc &>/dev/null ;done # 多核的话需要起多个进程丢到后台 1525.linux下如何打印出指定进程的进程树,而不是pstree打印全部的:pstree -ps pid 1526.sort 如果用-k指定了的话,那么n就要后置,如 sort -k2,3 -k1rn 1527.paste 把标准输入按列拼接成行: seq 20 |paste - - - - - # xargs -n5 注意:不同于多个输入:paste <(seq 3) <(seq 3 5) 1528.expect 在send密码之前有些系统需要 sleep 一下或者 set timeout=-1,否则导致密码在提示之前捕获而报错,可以expect -d 调试下 1529.删除 windows 下的 ^M 回车换行符: tr -d '[:cntrl:]' ; dos2unix;tr -d \\r;sed -i '/^M/d' # ctrl -v -M 1530.统计文件夹大小: du -hx --max=1 ; du -sk ;du -hsc 1531.关于shell/awk的随机数: 随机数伪随机,是根据随机种子计算出来的,随机种子确定,随机数就确定。 awk的随机种子默认是当天的天数。那怎么修改这个随即种子?srand() 一般用纳秒做随机种子,不过好像awk只能获取到秒,就是同一秒执行的话随机数还是一样的。 随机数是可能有重复的,因为是随机产生的。 1532.一个文件末尾没有换行符,怎么加个换行符:$'\n' tail -c -1判断,如果不是换行,就echo >>加一个, 或者你这样,先echo >>,然后在去掉空行,这样就不用判断了 很多windows编辑软件会很“贴心”得去除文件最后一个换行,vim是会很贴心的加上最后一个换行,除非是空文件,不动。 1533.关于shell解析一次,awk再解析一次转义符的例子: awk 'BEGIN{print "\\("}' # 双引号内的\\( 被shell解析了一个 \( echo "1(2)3"|awk -F '\\(2' '{print $2}' # ( 不转义是组合 )3 awk "BEGIN{print '1'}" # awk以单引号为分隔符,所以里面不能用单引号。除非你用""去掉单引号的作用,就像shell下一样 awk: ^ invalid char ''' in expression 1534.巧用 RS、RT 匹配双引号段,去掉非双引号空格: echo 'abc 234 fsdfds 555 "34 666 53242 " asaf tttttt'|awk -vRS='"[^"]+"' '{gsub(/ +/," ");printf $0 RT}' abc 234 fsdfds 555 "34 666 53242 " asaf tttttt # 注意双引号要偶数个出现,RT 会针对每一行进行动态变化。 1535.base64 的编码与解码:base64 -d <<<anVuZV8xMjAxQHFxLmNvbQo= 1536.用find 找到几千个文件,然后想用 xargs 结合 tar打包,为什么tar包里面只有部分数据: xargs --show-limits看下,如果你的命令超过命令行长度限制,会自动切分,用tar -r,这样就好了 1537.rsync 显示远端服务器目录列表:rsync -avz dst 1538.linux 下 .so文件找不到 一般是ld的cache目录没更新,执行了一下ldconfig,就正常了。 1539.变量不加双引号在某些特定情况下被解析为 IFS 而显示为空: a="";echo $a|xxd ;a=$'\n';echo $a|xxd ;a=" ";echo $a|xxd 空格和\n都是IFS,所以echo $a=echo, 所以要用"$a",因为不加双引号,空格被认为是IFS,跳过,因为只有零个参数,所以结果就是空 1540.用 read -N1 捕获 回车符 \n: read -N3 a echo "$a" && echo "$a"|xxd 1541.sed 中行范围扩展匹配: seq 10| sed -e{3,4,5,10}'s/.*/--/' #行范围不固定的扩展匹配 1542.sort -g 把科学计数法按普通数字排序 1543.删除乱码:LANG=C tr '[:punct:]' 123 1544.seq 等宽并指定分隔符: seq -w -s, 0 299 用echo 或者 for((i=1000;i<=1229;i++)); do echo ${i:-3}; done 或者 printf 格式化 1545.sort -k n.m 按某列字符排序:sort -k 1.1,1.1 -k 1.2n #第一列按字典排,第二列之后按数字排 1546.shell变量为了防止 word split,需要加上引号: june@~ 00:42:25> a=`echo -e "1\n2"` && echo $a 1 2 june@~ 00:58:38> echo "$a" 1 2 june@~ 00:58:42> 1547.找出bash数组是否有元素“匹配”(不是存在)给定字符串: a=(1 2 3 abc) && [[ "${a[@]}" =~ 'ab' ]] && echo '------match' # 也可以用 grep -q 1548.合并前两列:sed -r 's/\s+//' 1549.awk的asorti 是把下标按字典排序,可以得到新的下标数组与数组长度,二次引用即可获取原数组 value awk '{n=$1;getline;h[n]=h[n]"\n"$1}END{n=asorti(h,s);for(c=1;c<=n;c++)print s[c]":"h[s[c]]"\n=="}' 要数字排序需要把下标拿出来用 asort 函数,然后进行二次引用 1550.awk 跨行匹配,并用gsub替换返回匹配次数: awk '{$0=n$0;c+=gsub(/China/,"");n=$NF}END{print c}' 1.text 1551.grep -A -B实现连续多行匹配: seq 3|grep -A1 1|grep -B1 ^2 awk -vk1="abc" -vk2="efg" '{c++}$0~k1"$"{c++;getline n;if(match(n,"^"k2))print c-1":"$0"\n"c":"n}' filename 1552.关于 crontab 的星期和 月日的 and or 关系: 30 3 * * 1 dosomething , 是每周一3点半执行是确信无疑的了。 30 3 1 * 1 dosomething , 是当1号是周一的时候执行吗?不是!是1号,或者周一的时候执行。 crontab中的星期和日、月是一个“或”的概念,而非“和”的概念。 1553.awk、sed的缓冲问题: man awk :fflush([file]) #awk 不是,与系统缓存与文件大小有关。 man sed :-u, --unbuffered #sed 是因为他是行缓冲方式,遇到换行就会输出。 1554.sed N P D 的解释: 首先;你加了-n参数,不会默认输出pattern space里的内容,只有p或者P操作才会打印,你先清楚这点. 当第一行的时候,N读取下一行,注意这时候的行号已经是2了,PS里的内容是 1\n2; 因为不是第4行,所以不执行{ } 里的操作,执行完毕,因为-n参数不会输出PS里的内容. 这时候继续执行,已经是第三行了,因为第二行读走了,N操作,PS里的内容是3\n4,这时候行号是4, 满足4{P;D}条件,执行P,请查阅sed资料,P是打印PS里第一行的内容,那就是3输出到了屏幕. 1555.cp mv rm,默认都是不提示,加-i才提示,这三个命令的-f参数都不一样,好好看看。 23:57:29#tp#~> rm -f addsf 23:57:36#tp#~> rm -f addsf 23:57:37#tp#~> rm addsf rm: 无法删除"addsf": 没有那个文件或目录 23:57:39#tp#~> rm -i addsf rm: 无法删除"addsf": 没有那个文件或目录 23:57:42#tp#~> rm -f是不提示不存在的文件,rm 默认就是不提示是否删除,加上-i才是提示是否删除 1556.awk的精度问题: awk 'BEGIN{print OFMT;print 1335533180.170077-1335533180.169424;OFMT="%f";print OFMT;print 1335533180.170077-1335533180.169424}' %.6g 0.000653028 %f 0.000653 1557.head 和 tail 的正负数既可表示开头也可表示取到结尾xx处: head -c -2 # 除去一个文件的最后两个字节,也可以 dd 或者 sed '$s/..$//' 1558.查看文件以回车换行结尾:set fileformat 或者 xxd 换行符 \n ^j 0a LF 回车符 \r ^M 0d CR 如果是mac,用回车做换行符,那么你直接cat是看不到换行的。 1559.awk 索引index asorti 是按字典排序,因此如果数字的话以对齐位数后再排序: a[sprintf("%03d",$n)] 1560.curl -G 模拟 post/get 请求(默认是 post 方式),--data-urlencode 进行 urlencode 编码 curl -v -L -G --data-urlencode '我们' http://www.baidu.com/s curl -v -L -G -d "lat=41.225&lon=-73.1" http://localhost:5000/pulse # by default, calls POST. If you want to send a GET request,use -G 1561.urlencode 编码的其它几种方式: echo '手机' | tr -d '\n' | xxd -plain | sed 's/\(..\)/%\1/g' # 这里用到了 xxd,python的话有API可以直接调用 1562.urldecode 编码解码: printf $(echo -n "http://www.baidu.com/s?wd=%ca%d6%bb%fa" | sed 's/\\/\\\\/g;s/\(%\)\([0-9a-fA-F][0-9a-fA-F]\)/\\x\2/g')"\n" 1563.stat 查看数字权限: stat -c %a 1564.gzip 查看文件压缩完成时间:缺省情况下gzip会保留源文件的时间戳, 所以是查不到你想要的完成时间的 ls -lctr yourfile.gz 或者 gzip -c foo > foo.gz 1565.cat -v 编码: 21:44:47#tp#~> echo 中|xxd 0000000: e4b8 ad0a .... 21:49:36#tp#~> echo 中|cat -A M-dM-8M--$ 21:49:39#tp#~> d的十六进制是64,8的十六进制是38,-的十六进制是2d V的十六进制是56,P的十六进制是50。 其实就是系统的一种对应关系,中文在ascii里面没有,所以就这样表示了 1566.man的相关用法: man 5 crontab # 关于 crontab 的日期介绍 man不只是有1个,有1-8。man -a crontab 就查全部 man 文档了. man -f crontab,看有哪些帮助文档 man -a crontab,会一个一个man看过去,你按q以后进入下一个man # man man 1567.rsync复制原理: rsync 会在命令运行的初始阶段产生一个hash列表,里面列出所有要同步的文件和目录。 如果文件的大小在复制后有改变, 那么rsync 会尝试重新复制,几次尝试后,如果还是不一致,就会报个错。 1568.test -n/[ -n ] 问题: 在[ ]中, 如果只有一个参数, 那这个参数就被当成一个普通的字符串,并用 -n 测试其长度, 比如, [ -gt ], 相当于 [ -n -gt ],因此注意下面两者区别: [ -n "" ];echo $? ; [ -n ];echo $? 1569.SIGNKILL(9) 和 SIGNTERM(15) 的区别在于: SIGNKILL(9) 的效果是立即杀死进程. 该信号不能被阻塞, 处理和忽略。 SIGNTERM(15) 的效果是正常退出进程,退出前可以被阻塞或回调处理。并且它是Linux缺省的程序中断信号。 1570.sort排序会用到临时文件:默认 tmp 空间不足会报错: sort: write failed: /tmp/xxxxx: No space left on device linux的指定 -T 参数修改目录或者修改 TMPDIR变量 1571.printf ascii 与数字转换: echo "7249 81"|awk '{printf "%c %c\n",$1,$2}' # 为什么结果一样? echo "7249 81"|awk '{printf "%x %x\n",$1,$2}' 1c51 51 # 高位被丢弃了 echo "7249 81" | awk '{printf "%d %d\n",$1%256,$2}' echo '7249%128'|bc 1572.显示shell开启了哪些shell标志: $- The current shell flags, such as -x and -v. - Expands to the current option flags as specified upon invocation, by the set builtin command, or those set by the shell itself (such as the -i option). set [+abefhkmnptuvxBCEHPT] [+o option] [arg ...] echo $- && set -x && echo $- && set +x && echo $- 1573.top获取指定id的进程信息,-b 避免输出控制字符: top -p 25097 -n 1 -b|cat -A 1574.巧用gsub查找单词出现的次数:awk '{print $1,gsub("id","")}' 1575.脚本手动执行正常,crontab 无法执行: 由于 crontab 不加载 profile, bashrc之类的环境变量,而这其中受的影响很大比例都是PATH变量 所以养成好习惯:每个脚本之前就加上加载用户环境变量文件 1576.chattr 设置权限防止root删除: -rw-rw-rw- 1 root root 959301 May 15 15:40 .my_history gs_chatlog_2_207:/data # chmod 777 .my_history chmod: changing permissions of `.my_history': Operation not permitted gs_chatlog_2_207:/data # whoami root gs_chatlog_2_207:/data # lsattr .my_history -----a------- .my_history 解除-a限制:chattr -a 文件名 1577.awk或perl利用时间戳获取上一天日期: perl -e 'use POSIX;print strftime("%Y%m%d",localtime(time-86400))' awk -vnum=-2 'BEGIN{print strftime("%Y%m%d",systime()+86400*num)}' 1578.删除所有的空文件: find . -maxdepth 1 -size 0c -delete find . -maxdepth 1 -empty -delete 1579.vim可以编辑 tar.gz, tgz, zip 等压缩文件: vim some-archive.tar.gz 1580.临时忽略 SSH host key: ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no username@host When you SSH to a server whose host key does not match the one stored in your local machine's known_hosts file, you'll get a error like " WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!" that indicates a key mismatch. If you know the key has legitimately changed (like the server was reinstalled), a permanent solution is to remove the stored key for that server in known_hosts. 1581.找出页面的最后修改时间: wget -S --spider http://osswin.sourceforge.net/ 2>&1 | grep Mod Last-Modified: Wed, 08 Feb 2012 20:14:53 GMT 或者用 curl 替代: curl --head -s http://osswin.sourceforge.net | grep Mod 1582.先把整个文件的内容都显示出来然后再跟踪显示:tail -n+0 -f 1583.find -L 查找链接对应目录: 链接 /usr/local/my_lib -> /usr/lib/ find -L /usr/local/my_lib -name "*so" 1584.关于 rsync 的服务端与客户端: 1.1.1.1:/tmp是走的ssh 1.1.1.1::/tmp和rsync://1.1.1.1/tmp是rsync服务端 但是很多配置是ssh不支持的,而且这样你要开帐号,还要开ssh的帐号 否则直接虚拟帐号,比如debian啊什么的,开的rsync,难道把ssh帐号给你? 走ssh的话其实就是scp的升级版,少点数据传输。 rsync daemon 的话在 daemon 上控制权限,要开 daemon,ssh 的话 ssh 控制权限,要开ssh 1585.回车与换行符的终端输出: ^J \n 0A 换行符 ^M \r 0D 回车符 1586.BREs, EREs是否支持\s(PREs)和sed是否支持\s没有必然联系, 没规定软件不能扩展自己的匹配方法。 1587.获取文件的绝对路径:realpath filename # 也可以 pwd + "/" + filename 1588.tar.gz 不能直接 -r, 要先解压成 tar,再-r,最后再压缩成 tar.gz 1589.vim 列模式: 将光标放在需要选择列的第一个字符上,在一般模式中,按下“Ctrl+v”, 然后使用“↓”或“↑”进行块字符的选择,选中的地方会反白显示, 可以使用使用“y”进行复制,“p”进行粘贴,“d”进行删除操作。 或者: Ctrl-V 选块,然后shift-i,shift-a或者c,x进行改写操作。双击 Esc 退出确认生效。 1590.read读取标准输入的问题: while : # 此时 while循环里的块 FD0 已经被 <filename.txt 覆盖,类似局部变量优于全局变量 read # read要读入标准输入可以 read var <&1 或者 read var </dev/tty done < filename.txt 1591.tcpdump -s0 不限制包长度 抓包: tcpdump -s0 -w a.pcap host 8.8.8.8 and tcp port 80,然后a.pcap传到本地,用wireshark打开。# wireshark 可以认为是 tcpdump的图形界面 1592.覆盖文件需要对文件有w权限,删除需要对文件所在目录有w权限,而不需要对文件有w权限: 一个目录里面有多少文件都是记录在目录项里的。只要让这个目录不包含某个文件,就相当于删除这个文件了。 所以删文件的实质是:使其所在的目录不再包含这个文件。所以对目录有写权限就行了。 1593.巧用 !* 匹配单词边界,实现单词字符分割: sed 's/!*/ /g' <<< 'ab1c2pha' # 非任意字符,即为单词边界,等价于 sed 's/\B/ /g' <<< 'ab1c2pha' echo "ab1c2pha" |sed 's/./& /g' # sed 's/\w/& /g' awk -vFS="" '{$1=$1}1' <<< ab1c2pha 1594.用printf输出一行终端字符: printf "%$(tput cols)s\n"|tr ' ' '=' 1595.查看某个进程加载的环境变量信息: tr \\0 \\n </proc/$pidxxxxx/environ 或者如果 unix、freebsd 没有 environ,那就试试下面的: cmdpid=`pidof cmd` && ps eww -p $cmdpid 1596.grep -l 实现打印匹配字符串的文件名,匹配并立即退出下一个,awk 的 exit 或者 nextfile 也可以实现。 1597.将多行变成一行的几种方法: tr、xargs -n1、awk NF+=0 ORS=" "、echo $(<file) # paste -s 或者 column 也行 1598.每两行合并为一行: sed '$!N;s/\n/ /' urfile awk '{printf (NR%2)?$0 FS:$0"\n"}' urfile paste -s -d ' \n' urfile # -d 后面的分隔符是个 list xargs -n2 < infile 1599.shell下的8进制转码问题: 14:26:38#tp#~> echo $'\270\264\274\376' 复件 14:26:55#tp#~> 这个也可以,我现在把终端编码换到gbk了,就不用iconv了 14:21:17#tp#~> awk 'BEGIN{print "\270\264\274\376"}'|iconv -f gbk -t utf-8 复件 14:21:24#tp#~> # 直接 echo转不了,这里awk把\270\264转换成汉字 ,iconv是转换编码 echo -e '\0270\0264\0274\0376'也可以 不过还是echo $'\270\264\274\376'方便,不然还要每个\都加个0。# echo $'' 相当于 echo -e '' 按理说八进制都0开头确实比较好 不过现在好多都可以去掉0 不懂为什么这么不和谐。 bash 3.00.15确实是这样的,后来的bash改掉了,不用加 0 了。 其实 python -c 'print "\270\264\274\376"' 也行。 1600.xargs -d 支持分隔符: echo "abc,dd,bach,dong,jing,shang,china,bejing" | xargs -d, -n1