shell学习笔记(4)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
301.awk不处理最后一行:1、根据wc -l,3、读完一行,再读一行,判断是不是行尾,4、tac,从第二行开始搞起
2、保存上一条记录,每次处理前一处记录,
awk '{if(NR>1)print a;a=$0;}' ;awk '{if(p)print p}{p=$0}',awk '{if(p)print p};p=$0'相当于awk '{if(p)print p}{if(p=$0)print}'
302.awk具有解释类脚本的便捷,又有编译程序的效率。awk内部采用的是编译的过程,词法上采用了yyacc解析成语法树,外层用运用c代码对树递归调用。做为一个便捷的shell utility,效率上已经相当不错了~~~perl比awk更接近于语言,脱离了工具的固定模式约束,拿awk跟perl比,就像拿汽车跟交通公具比,没有多大意义
303.本地和远程判断 设备存不存在
igi@igi-gentoo ~/test $ ssh localhost test -e /dev/shm
igi@igi-gentoo ~/test $ echo $?
0
304.wait 命令 保证进程同步 等待一个子进程结束 多个并发就用多个wait; 等待jobs完成
305.sed中的 \0 等价于 & ,匹配时是贪婪匹配,不支持非贪婪,但可以x[^X]x变相的非贪婪。.*的优先级是最低的:echo "IP 1234"|sed 's/\(IP\).*\([0-9]\)/& Add:/'
306.转换中文:echo %E4%B8%AD%E5%9B%BD|sed 's/%//g;s/^/0:/'|xxd -r
307.shell启动-》读入history文件->维护当前history(进程环境里)-> -a:写入文件->继续维护(进程环境里)->退出shell(写入文件)
308.查看进程树:pstree -p 6767
309.sed中的s///m的m是多行
310.怎么精确地看一个进程的内存使用量: ps -eo cmd,rss
311.管道就是多一个启动进程的时间,如果你的进程运行的时间都很短,那么多一个管道对你的影响很大,如果你的进程运行时间很长,那么影响不大。
还有数据在两个进程中传递也需要时间,不过内存里面应该很快的。
312.less 里搜索字母大小写无关: 运行less的时候加-i ; man 大小写无关 ;查看大文件的时候还是less好。vi不行
313.cron里面%是换行,要转义
314.%s/.\{80\}/&\r/ sed中每80个字符添加一个换行
315.关于awk gsub返回值的问题:gsub返回的是替换了几次的次数,要想获取改变的值,直接打印变量或者被替换值重新赋给某一变量。
echo "qqqq|2010-10-11 23:21:23|www"|awk -F"|" '{print gsub(/-| |:/,"",$2)}'
echo "qqqq|2010-10-11 23:21:23|www"|awk -F"|" '{gsub(/-| |:/,"",$2);a=$2;print a}' 或者直接print $2
316.grep返回匹配部分并且匹配单词:echo "ass23(30123)we---b(30124)---c(30125)"|grep -Eo "\<[0-9]+"
echo 'a(30123)---b(30124)33---22(30125)'|perl -nle 'print join "\n",/\((.*?)\)/g'
317.awk跳转到下一个文件:nextfile ;awk里的控制语句:continue,break,exit,nextfile
318.sed、awk提取单引号内字符串:
[root@rac0 ~]# echo "weeteassdf='hello'weeteassdf='hello'weeteassdf='hello'weeteassdf='hello'weeteassdf='hello'weeteassdf='hello'we
eteassdf='hello'weeteassdf='hello'"|sed "s/[^']*'\([^
'*]*\)'/\1/g"
hellohellohellohellohellohellohellohello
[root@rac0 ~]#
或者:awk来处理 awk -v RS="'" -F"'" 'NR%2==0' ; -F是参数,FS、RS是内部变量要用-v或者放在BEGIN里面,亦或者放在最后awk -v RS="'" "NR%2==0" FS="'"
echo "assdf='hello'"|sed "s/.*='\(.*\)'/\1/" 双引号里面的单引号已经失去原意,因此单引号不用转义了
319.关于单双引号的转义问题:a=3;echo "'$a'" :'3' ; a=3;echo '$a' :$a 双引号去掉了单引号的特殊意义,所以变量被shell解析了
双引号:除$ ` \ 仍保留其特殊意义外,其余字符均作为普通字符对待
单引号:$ 也被作为普通字符对待 ;查man bash 里的"QUOTING"一节,会有更多的收获
echo "'$a'" 最外面的" " shell 解析,echo不解析;
find等其它命令会解析引号内的内容,比如find -name "*.txt" 这个*就是find解析的
320.shell中有些用分号不行,一定要换行的。 而且lable a一定要换行,否则还会报lable不能超过8个字符。。unix下b和t有关系 ,要换行。
321.awk获取参数:
1、提示用户输入参数getline:awk 'BEGIN{print "input sth";getline var <"-" ; print var}' # 其中 "-" 就是标准输入,很多工具都支持 "-" ,比如tar/cat等。
2、获取awk脚本的位置参数:awk 'BEGIN{print ARGV[1],ARGV[2]}' a b
322.uniq没法取出某列重复的,只能某列以后都重复的。
323.有个后台程式在运行,用ps -aux|grep programm可以看到,到切换到此用户后用jobs为何看不到?
jobs是对当前shell的 ,不是对用户的 , 你切换用户后 那个进程对你当前用户来说就已经是在后台运行的 ,job是 是显示 你当前shell的已经启动的
你执行一个sleep 99 &然后ps -fe|grep sleep看看,然后退出,再ps -fe|grep sleep看看区别,进程的父进程变了。
前面哪个sleep是哪个shell的子进程,后面哪个是init的子进程 ,那如果我想把它再调到前台可以吗?没办法的 。
324.命令后面即使+&退出终端,命令就自动结束了:看发行版的,不同发行版处理不一样,还有用nohup或者disown过后就可以了。
325.for i in `cat ems.txt` 这个要打开这个文件N次,done >是打开一次,各有优缺点。
>>次数多,每次数据量小,>次数少,每次数据量大,如果数据量很大,就用>>,免得内存不足。
326.()和<来传数据:grep -vf <(cut -f1 a.txt) b.txt
327.看内核还可以:cat /etc/issue
328.find查找时间段文件:那还要加个grep。find的printf就可以打印时间的。
329.sh apply.sh 2>&1 : 2是错误输出,1是标准输出,2>&1表示把错误输出放入到标准输出里面
330.查找刚好包含16个字母的单词: grep -w “[a-zA-Z]\{16\}”file ; grep -w "^.\{16\}$" file
331.top按了R、1、P分别表示逆向排序、显示所有cpu、翻页
332.对find . -path ./src/emacs -prune -o -print的几点
说明:
find 表达式由 options, tests and actions 三部分组成 ,如果actions 没有 ,执行-print ,-prune 也是action ,所以有action 不执行-print
find . -path './scripts' -prune -o -name '*.pl' -print
你看这个 -path './scripts' 是test -prune 是action , 如果是./scripts 下的文件 那test就是真,-prune 总是真 所以合起来就是真
但是因为没有-print,所以其实啥也不干 , 因为前面是真 所以-o 后面的都不执行
333.正确的使用错误重定向:2>
16:00:41#www#~> ls sfdsd|grep abc 2>/dev/null
ls: 无法访问sfdsd: 没有那个文件或目录
16:05:25#www#~> ls sfdsd 2>/dev/null|grep abc
16:05:34#www#~> #还有,如果错误实在内部产生的,你在外部2>是没用的。
334.awk也支持sed的&:echo "a b c"|awk '{gsub(/.*/, "&'$a'");print}'
335.eval解析:
我为SUN狂.marvel
16:27:13#www#~> a=1
16:27:16#www#~> b1=2
16:27:18#www#~> eval echo \$b$a
2
解析两次,第一次得到$b1,然后得到2
如果2是作为一个变量名呢 ? eval echo $\{$(echo $ABC$DEF$H)\} ;$ (A=aa;B=bb;aabb=T; eval echo \$$(echo $A$B));c=$(eval echo \$b$a)
336.设置时区:date -u ; tzselect ;TZ='Asia/Shanghai'; export TZ
337.awk巧设状态值(标志位)实现模式打印:
seq 9|awk '/3/{a=1;next}/5/{a=0}a==1{print $0}' #就是找到-------------那行,然后标记开始打印,然后找到===========那行,标记结束打印
awk 'BEGIN{RS="[=-\n]+"}NR%2==0'
awk 'BEGIN{RS="[-=]+"}{print $2}'
awk 'BEGIN{RS="\n=+\n";FS="-+\n"}{print $2}' da #RS是\n=+,所以没把最后的换行算进去, cat da|tr '\n' ' '看的清楚点
awk 'BEGIN{FS="[-=\n]+";RS=""}{print $2"\n"$4}' jun.txt #怀疑是[]里面的\n被还原了,[]里面-一定要放最前面,或者最后,ascii 顺序问题 ,结尾比开头小,不同字符集里面=-\n的意思不一样
awk '/---/,/===/' file|awk 'NR>1{if($0 ~/===/)exit;print}'
cat file|sed '1,/---/d;/===/,$d'
1
-
2 8 0 9
=
3
--
4
==
5
338.vi:用一条命令删除第 50 行到 100 行:50,100d
339.除了手动单个赋值、for循环赋值之外,split赋值也是不错的想法:echo "123:456"|awk '{split($0,a,":" ); print a[1]}'
340./etc/skel下有什么 ,创建用户时 home 目录就会有什么 .profile; useradd可以用-k参数指定其他目录,不一定要/etc/skel
341.echo与bash的解析问题:单单`` 或 $() ,获取到是被\转义的引号,也就导致后面的命令被切开了;建议你多用strace ,可以看到shell是解析命令后的结果
igi@igi-gentoo ~/test $ str=$(awk 'BEGIN{printf("date +\"%T $(date)\"\ndate\n")}')
igi@igi-gentoo ~/test $ echo $str
date +"%T $(date)" date
igi@igi-gentoo ~/test $ echo "$str"
date +"%T $(date)"
date
igi@igi-gentoo ~/test $ eval "$str"
13:33:13 Tue Nov 16 13:33:13 CST 2010
Tue Nov 16 13:3
3:13 CST 2010
igi@igi-gentoo ~/test $ eval $str
date: extra operand `date'
Try `date --help' for more information.
342.awk数组判断重复并去重:awk '{b[$1]=++a[$1]} {if(b[$1]==1){print $0 > "file1" }}'
343.# 随机生成n1个不重复的范围在1-n的整数
awk -v n=$n -v n1=$n1 'BEGIN{for (i=1;i<=n1;i++) {srand();while (1) {v=int(rand()*n)+1;if (!(v in a)) {a[v];print v;break}}}}' >rand.txt
344.awk交替读入两个文件:getline var < file ,用完后记得close(f)
for((i=1;i<=2;i++)) do awk -v num="${i}" 'BEGIN{max=0;f="a"num}{getline a < f;if($0-a >max || a-$0>max)max=$0>a?$0-a:a-$0;}END{close(f);print max}' b"${i}"; done
345.需要修改其中时间部分,实现从2008年3月7日10时00分至2008年8月30日10时00分的循环。以小时为间隔。
while :
do
echo -n "sh_procman /home/gg/tables/sysman.cfg" `date -d "+$i hour 2008-07-30 09:00" '+%Y %m %d %H 00 manu'`
echo
t=`date -d "+$i hour 2008-07-30 10:00" '+%Y %m %d %H 00'`
i=`expr $i + 1`
if [[ `echo $t|grep "2008 10 30 10"` ]]
then
exit
fi
done
346.去掉匹配行上面的空行并插入一个分页符: sed 'N;s/^\nUrpattern/\f&/;P;D' urfile
347.大多数linux文件系统并不记录文件创建时间,创建文件时间并非posix标准
348.匹配的文件名或者字符串中含有-字符怎么办:用--字符关闭-代表命令选项的含义即可,例如:grep -i "ooo" -- "-filename"
349.grep ... file1 | awk ... file2的话管道里面的信息被丢弃的 ;一般命令都不会指定文件再加管道的, 有文件的话会忽略管道数据的
10:29:59#www#~> seq 5 >a
10:31:19#www#~> seq 3|awk '1' a
---------------------------
10:31:26#www#~> seq 3|awk '1'
---------------------------
10:33:27#www#~> echo abc|cat a
cat在带文件的时候也忽略管道的,sed也是
---------------------------------
你想实现先管道后file,可以这样:
awk ... <(grep ... file1) file2
或者:先管道后文件,试试这样
grep ... file1 | awk ... - file2 # -表示从标准输入里面读入
350.一般多个后台命令的时候,wait等待他们一起结束后再操作其他 或者直接逗号隔开。wait会等待其他后台进程的 ,
除非那个任务不是后台进程了,比如被disown了。 远程没关系的 。那还是后台进程啊,只要jobs有输出,那么wait会继续等待的。而nohup会有影响的。前台就一个wait,不用等待。
351.grep采用p正则提取ifconfig的ip:grep -oP '(?<=:).*(?=\s+Bcast)' <(ifconfig)
352.top翻页:top -bn1|less
353.sort不支持多字符分割符:--t被sort直接无视了,排序应该没效果 ;-t"--"或者-t"aa"都会报错的
sort -k2 -t"-" a
bb----1
qq----2
cc----3
354.shell的%扩展提取字符串:a=192.168.3.1 ;echo ${a%.*} ;192.168.3
355.ps自定义输出列-o:ps -o cmd,rss,stat,pid,ppid
356.ps -o cmd 命令+参数; ps -o comm只含有命令;ps -eo cmd|grep ^
command$这样更严格点
ps -o args : args是整个命令行comm只是命令
357.如何踢掉ttyp1登陆用户:
man skill,man pkill /-t
pkill -9 -t pts/0
pkill -t /dev/tty1(不报错但是踢不掉,要去掉/dev/)
358.pam限ip和用户用的是哪个模块: pam_access ; /etc/pam.d/sudo 里调用pam_time.so
359.设置普通用戶su 到某個用戶不需要輸入密码: sudo su 设置NOPASSWD
360.查看文件编码:file和enca;转换编码:iconv
361.tar提示去掉文件名前的 / ; 这是tar的安全设定:假如你打的包里有etc,如果不去掉/ 就成了/etc,就会覆盖原有目录!不加-P就会去掉/,使用相对路径了。
362.vi删除末尾的换行符或者合并两行:J;nJ合并从当前行起的n行
363.<< 或者 <<< :here string(即插即用文本) awk '{system("useradd -m "$1"; passwd "$1" --stdin <<<"$2)}' file
364.shell expr错误状态返回码:
Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null or 0, 2 if
EXPRESSION is syntactically invalid, and 3 if an error occurred.
365.sed或者提取:echo "part0,part1|part2|part3"|sed 's/|\|,/\t/g' 或者 echo "part0,part1|part2|part3"|sed 's/[|,]/\t/g'
366.开头或结尾添加字符:sed 's/$/,23456/' file 或者直接修改原文件:sed -i 's/$/,23456/' file
367.shell的参数扩展parameter expansion:
${varname#pattern} shell 像文件名扩展中那样扩展 WORD,并从 PARAMETER 扩展后的值的开头删除最短的匹配模式(通配符的非贪婪匹配)。使用 ‘@’ 或 ‘$’ 即可删除列表中每个参数的模式。
##、%%代表贪婪匹配 #是从前向后匹配、%从后向前匹配
${PARAMETER/PATTERN/STRING}。此处是贪婪匹配,PATTERN 附上前缀 #,相当于正则的^;在值末尾匹配模式,则附上前缀 %;相当于$。如果 STRING 为空,则末尾的 / 可能被忽略,匹配将被删除。使用 ‘@’ 或 ‘$’ 即可对列表中的每个参数进行模式替换。
${PARAMETER//PATTERN/STRING} 对所有的匹配(而不只是第一个匹配)执行替换。相当于正则中的g
${PARAMETER:=WORD} 如果 PARAMETER 没有设置或者为空,则 shell 扩展 WORD 并将结果指派给 PARAMETER。这个值然后被替换。不能用这种方式指派位置参数或特殊参数的值。
如果变量没有值或者空才替换:unset x;y="abc def"; echo "/${x:='XYZ'}/${y:='XYZ'}/$x/$y/"
${PARAMETER:+WORD} 如果 PARAMETER 没有设置或者为空,则不作替换。否则 shell 扩展 WORD 并替换结果。
如果变量有值才替换:unset x;y="abc def"; echo "/${x:+'XYZ'}/${y:+'XYZ'}/$x/$y/"
368.parameter expansion的替换与提取:
长度:${#p} ;访问第15个参数:${@:15:1} 是一种直接访问参数 15 的方法 ;${x:3:5} 变量x的子集
chj@linux-xzlr:trunk\> AA="a bc d ef"
chj@linux-xzlr:trunk\> BB="d"
chj@linux-xzlr:trunk\> echo ${AA%%$BB*}
a bc
cjash@linux-sdik:dl\> AAA
=abcdef
cjash@linux-sdik:dl\> echo ${AAA:2}
cdef
cjash@linux-sdik:dl\> echo ${AAA-2}
abcdef
-bash-3.00$ echo ${AAA: -2}
ef
-bash-3.00$ echo ${AAA::2}
ab
-bash-3.00$
-bash-3.00$ echo ${AAA:-2} #:-2无效,直接被无视了~
abcdef
-bash-3.00$
cjash@linux-sdik:ppp\> AAA=abcabcabc
cjash@linux-sdik:ppp\> echo ${AAA%${AAA: -2}}
abcabca
cjash@linux-sdik:ppp\>
369.查看bash数组下标:a=(b c d r);echo "${!a[@]}"
370.BRE匹配null字符:(认为比完全不匹配还长的匹配)
echo abc | sed 's/b*/1/' ----> 1abc
echo abc | sed 's/b*/1/g' ----> 1a1c1 #完全一致的匹配指的是自最左边开始匹配,针对每一个子模式(()锚点)、自左至右,必须匹配到最长的可能字符串。
371.赋予文件属性:chattr +i -u filename (谁也无法删除) ;chattr -i filename 这样下才可以删 ;用lsattr 查看是否有这个属性
372.将文件乱序随机读出:awk 'BEGIN{srand()}{b[rand()NR]=$0}END{for(x in b)print b[x]}' data
随机数+每行linenumber --对应--> 那一行的内容 即为所构造的随机函数b[rand()NR]。机率非常小,但不能排除重复可能。用 b[rand()" "NR]如何? 也可用逗号b[rand(),NR],默认是\034字符,散列的思路真棒
373.产生一个五十几万行的随机文件,大约有38M:od /dev/urandom |dd count=75000 >data
374.随机取出一列:while read line;do;array=($line);echo ${array[$((RANDOM%${#array[@]}))]};done
376.设置vi光标横线:set cul cursorline
377.ps单独显示pid与命令路径:ps -eo pid,cmd ;ps -eo pid,comm
378.关闭vi在粘贴时的自动缩进功能:set paste
379.删除空格和空行:sed '/^\s*\r\?$/d'
380.让wget完了以后 执行我后面的程序: wget; wget && ; wget -o >/dev/null
381.查询依赖包:rpm -qf XXX 或者 yum search XXX;yum install XXX
382.软连接 只能考虑rsync,不能用scp
383.ps所有字段格式:ps L
384.直接scp到本地是调用cp的,这个当然可以复制符号链接的,主机名的话就不能复制符号链接的scp -rp 1/* localhost:~/test/2/ ;apue,第一版,第四章,74页,-L跟随,-P不跟随
也可以打包后再scp:tar -czvf - /src/dir | ssh remotehost "(cd /dst/dir ; tar -xzvf -)"
385.取得系统上月时间:date +"%Y %m" |awk '{$2=$2-1;$1=$1+$2/12;sub(/\..*/,"",$1);if($2==0) {$2=12;$1=$1-1;} printf("%s%02d\n",$1,$2)}' ;date -d "a month ago" +%Y%m
386.命令嵌套命令多用$(),少用``:a=$(echo "$(date +%s)/600"|bc) ;date +%s|awk '{printf("%d\n",$0/600)}'
387.vi内使用tr:在tr命令前要加上您希望处理的行范围和感叹号 (!),如 1,$!tr -d '\t'
388.tr替换的一一映射问题:这样就有个问题,如果二个字符集的字符个数不一致如何处理
1:第一字符集个数多于第二字符集 2:第二字符
集个数多于第一字符集
第二种情况,直接把第二字符集截断就是
第一种情况有二种解决方法1.1:截断第一字符集 1.2:扩展第二字符集 ,默认采用的是1.2,-t就是用的就是1.1
389.按指定域去重:awk '{a[$5]++} a[$5]==1' d1
390.获取HTTP的头部信息:wget -S
391.rename重命名文件,把文件名中的a改成cda:rename a cda a.* ;rename 's/^a/^cda/' a.*.txt 不过不同发行版上的rename不一样 ,先看看man
392.即插即用文本重命名:ls a.*|while read old; do new=$(sed s/^a/cda/ <<<$old); mv $old $new; done
393.bash的命令扩展替换功能:for i in b.*;do mv $i ${i/b/c};done
find . -name "*linshi*"|sed 's:\./\(.*\):mv \1 cd\1:g'|bash
394.grep -l 打印匹配文件名;grep不是按行扫描的,很快。 是while不是for在循环
395.指定OFS后,需要有点什么变动,才能使新OFS生效,但是我们不需要什么变化,于是说一句废话,假装给$1一个新的值:$1 awk -F"/" '{NF=NF-1;OFS="/";$1=$1;print $0}'
396.查看bash快捷键:bind -p | grep -F "\C"
397.查看find支持的正则类型:find -regextype a
398.查看语言字符集列表:locale ,修改语言项:export LANG="zh_CN.GBK",export LC_ALL="zh_CN.GBK" ;/etc/profile 或者/root/.bash_profile中修改
399.后10位字符相同的去重:awk '!a[substr($0, length()-9)]++' #自己补全 rev urldata|sort |uniq -w 10|rev > urldata2 #uniq只对连续的重复有用,-w前反转
400.#!/bin/bash和#!/bin/env bash有什么区别:当bash不在bin下面时,后种写法更安全,他能根据env自动找到bash