shell编程三十六问
时间:2009-03-12 来源:lxl0121
一、
$((10#$i)) 是什么意思?
当作10进制的数,输出它的值(十进制表示)
比如:
$echo $((2#101)) #2进制的101 == 5
5
$echo $((16#abcd)) #16进制的abcd
43981
$
二
在CU上面awk 看到一个SHELL脚本的实例/path/to/1/domain/abc.com转换成/path/to/1/domain
用的方法awk 'BEGIN{FS=OFS="/"}NF--' urfile
不是很理解NF--这里面的意思是什么。请帮我解释一下
awk 'BEGIN{FS=OFS="/"} NF--' urfile 等于
awk 'BEGIN{FS=OFS="/"} NF--'{print $0} urfile
假如一行有5个域,NF就等于5,NF--后,NF就等于4,而“NF--”的值也变为4,因为4非0,所以执行默认的动作{print $0},即打印前4个域(因为此时该行的NF变为4了)
依据以上,当文件urfile中存在空行(即NF=0)时,NF--后NF将是负数,所以以上命令肯定会报错,可以试试。
三
shell里怎么能获得某年某月的天数呢
cal 09 2008 | xargs | awk '{print $NF}'
cal 09 2008 |sed -n '3,$p' |awk 'BEGIN{sum=0}{sum+=NF}END{print sum}'
四
请教个问题,如我现在有个文档,内容如下:
1.234 2.458
2.345 3.489
4.795 7.99397
45.748 6.45994
896.767989 8.45675
。。。
怎样才能得到结果如下:
1.23 2.45
2.34 3.48
4.79 7.99
。。。
即这个列的数值都是保留两位小数。
哪位可以帮忙啊?
多谢!
awk '{for(i=1;i<=NF;i++)printf("%.2f\t",$i);printf("\n");}'
awk '{printf("%.2f\t%.2f\n",$1,$2) }' urfile
五
有这个一个文本,error_log,有以下内容:
222.222.222.222 1217976832 2008-08-06_06:53:52
总共有3段,第一段是ip地址,第二段是时间戳,第二段是对应的时间。
现在想实现,查找到这个ip地址后,修改时间戳和时间戳对应的时间为当前时间。
sed '/222.222.222.222/s/.*/date +"222.222.222.222 %s %Y-%m-%d_%H:%M:%S"/e'
gawk:
awk '$1~/222.222.222.222/{$2=systime();$3=strftime("%Y-%m-%d_%H:%M:%S")}{print}'
六
现有一个文件deal_proc.dat,其内容如下:
exec testdb..sp_addproc 'hello world'
exec testdb..sp_modproc 'hello world'
exec testdb..sp_delproc 'hello world'
想得到文件deal_proc_new.dat,其内容如下:
exec testdb..sp_addproc 'hello world'
go
exec testdb..sp_modproc 'hello world'
go
exec testdb..sp_delproc 'hello world'
go
sed 's/$/\ngo/' urfile
awk '{print $0"\ngo"}' deal_proc.dat
sed 'a go'
As a GNU extension, if between the a and the newline there is other than a whitespace-\ sequence, then the text of this line, starting at the first non-whitespace character after the a, is taken as the first line of the text block. (This enables a simplification in scripting a one-line add.) This extension also works with the i and c commands.
七 将每两行连接成一行
将每两行连接成一行(类似“paste”)
sed '$!N;s/\n/ /'
$!N是表示如果不是文件的最后一行,就把下面的一行的内容append到当前的pattern space中,中间用\n分隔
八
有如下一个文件n行的文本
wwer swedf sdf sdfdsf iiiadf
er 45 ii 89
ei 87 kd sdf
......
想要实现,从第二行起对每个字符串加""
wwer swedf sdf sdfdsf iiiadf
"er" "45" "ii" "89"
"ei" "87" "kd" "sdf"
.....
请问如何实现呢
sed '2,$s/[^ ]\+/"&"/g' urfile
sed 1d filename | awk '{for(i=1;i<=NF;i++){printf("\"%s\" ",$i)}print ""}'
sed '2,$s/[^ \t]\+/"&"/g' urfile
sed 's/[^ \t]\+/"&"/g' abc
如果包含"-"怎么办呢
输入是
sadfa sfs fsdfs-sdfs
希望输出是
"sadfa" "sfs" "fsdfs-sdfs"
用二楼和五楼的都没有问题的,主要是把[^ \t]中的 \t替换成你的分隔符就行了。
三楼的第一行没有了吧。
九
将数据文件中的每一个首字母大写
echo'welcome to chinaunix!'|awk '{for(i=1;i<=NF;i++)printf toupper(substr($i,1,1))substr($i,2,length($i))" ";printf "\n"}'
十
把两列之间的不管有多少空格都替换为一个空格
如下:
aaa 1
bbb 2
vv 432
adb 4
替换为
aaa 1
bbb 2
vv 432
adb 4
tr -s ' ' filename
cat file | sed 's/ \{2,\}/ /g'
十一
文本内容
a.txt
type {
sfjslkfjslfjslf
lsjflsfjslfjs
sljfslfjslf
}aa
type {
sfkhsfkshf
141414lsjflsfjmb
s474ljfslfjslfm54
}bb
type {
098dgs
vnxvsb
zczgmvs
}cc
type {
blddgdlgj
d;gkdgkd
lkdjgld
}bb
...
现从文本a.txt中取出 type{...}bb的内容
结果:
type {
sfkhsfkshf
141414lsjflsfjmb
s474ljfslfjslfm54
}bb
type {
blddgdlgj
d;gkdgkd
lkdjgld
}bb
awk -v RS="" '/}bb/' a.txt
编个sed的
sed -n '/type/{:a;N;/\}/{/bb/{p;b};d};ba}' a.txt
十二
如题,我想把我工作目录下的所有文件夹都改成小写,要用什么命令?我只会用mv一个一个的改,好累........
最终程序代码:
#!/bin/bash
for f in *; do
[ -f "$f" ] && continue
g=`expr "xxx$f" : 'xxx\(.*\)' | tr '[A-Z]' '[a-z]'`
mv "$f" "$g"
done
if [ -d file ]
then
rename
fi
for f in *; do
[ -f "$f" ] && continue
g=`expr "xxx$f" : 'xxx\(.*\)' | tr '[A-Z]' '[a-z]'`
mv "$f" "$g"
done
十三
文件反序
sed '1!G;h;$!d' oldfile >newfile 文件反序
具体怎么理解,
1!是什么意思
$!是什么意思
1!G表示除了第一行以外,其余行都执行G命令;
$!d表示除了最后一行以外,其余行都执行d命令。
给你一个实例更好~~~
cat testfile:
12
34
56
sed -e '1!G;h;$!d;' testfile
执行第一行命令:h;d; 后hold space从null变为12\n而pattern space则从12\n变为NULL
执行第二行命令:G;h;d; 后hold space从12\n变为34\n12\n,而且pattern space从34\n变为NULL
执行第二行命令:G;h; 后hold space变成56\n34\n12\n而pattern space从56\n变成56\n34\n12\n
然后打印pattern space
十四
例如:
Conting1
ACGTAGTCAGTACGATGC
AGTCGAGTGACGTGAGCG
ACGTACTAGCTAGCTATC
Contig2
ATGCTAGCTAGCTAGCTT
TTCGATCGTAGCTAGCGT
CTAGCTAGCTAGCTATCG
用什么命令将序列合并成一行,不要空格:
Conting1
ACGTAGTCAGTACGATGCAGTCGAGTGACGTGAGCGACGTACTAGCTAGCTATC
Contig2
ATGCTAGCTAGCTAGCTTTTCGATCGTAGCTAGCGTCTAGCTAGCTAGCTATCG
Conting1
ACGTAGTCAGTACGATGC
AGTCGAGTGACGTGAGCG
ACGTACTAGCTAGCTATC
Contig2
ATGCTAGCTAGCTAGCTT
TTCGATCGTAGCTAGCGT
CTAGCTAGCTAGCTATCG
用什么命令将序列合并成一行,不要空格:
Conting1
ACGTAGTCAGTACGATGCAGTCGAGTGACGTGAGCGACGTACTAGCTAGCTATC
Contig2
ATGCTAGCTAGCTAGCTTTTCGATCGTAGCTAGCGTCTAGCTAGCTAGCTATCG
cat Conting1|tr -d '\n' >Conting11
cat Contig2|tr -d '\n' >Contig21
cat Contig2|tr -d '\n' >Contig21
四行变二行,第1行复制,后3行合并?
awk 'NR%4<=1{printf("%s\n", $0)}NR%4>=2{printf("%s", $0)}'
awk 'NR%4<=1{printf("%s\n", $0)}NR%4>=2{printf("%s", $0)}'
system_finger.txt内容为:
fc7:2.6.23.1
Fedora release 7 (Moonshine)
fc7:2.6.23.1
Fedora release 7 (Moonshine)
查找下资料知道用awk可以完成这项艰巨的任务。
awk '{if(NR%2==0){printf $0 "\n"}else{printf "%s:",$0}}' > system_fingerprint.txt
cat system_fingerprint.txt 看看
fc7:2.6.23.1:Fedora release 7 (Moonshine)
十五
原文件如下:
select abc form dbs where a=b and b=c
select abc
form dbs
where
a=b and b=c
select
dbs
where
a=b
and
b=c
select * from dbs where a-b
要删除包含where a=b and b=c的行(也就是删除红字的行),但有可能是二行或是三行组成的。
结果如下:
select abc
form dbs
select
dbs
select * from dbs where a-b
因为包含的内容行数不固定用awk处理起来比较难,不知道sed可不可以处理,谢谢了!
select abc form dbs where a=b and b=c
select abc
form dbs
where
a=b and b=c
select
dbs
where
a=b
and
b=c
select * from dbs where a-b
要删除包含where a=b and b=c的行(也就是删除红字的行),但有可能是二行或是三行组成的。
结果如下:
select abc
form dbs
select
dbs
select * from dbs where a-b
因为包含的内容行数不固定用awk处理起来比较难,不知道sed可不可以处理,谢谢了!
sed '/where/{:a;s/[ \n]*where[ \n]*a=b[ \n]*and[ \n]*b=c//;tb;/\nwhere/{P;D;};N;ba;:b;d}' urfile
:a 冒号用来定义标签,名字可以自定义。:a定义标签a,用于指令跳转,循环处理。
tb t命令会在s///成功后跳到b标签;失败则不跳转,继续后面的指令。省略标签时,跳到脚本末尾,亦即开始处理下一行
ba 是无条件跳转到标签a。省略标签a则到脚本末尾
tb t命令会在s///成功后跳到b标签;失败则不跳转,继续后面的指令。省略标签时,跳到脚本末尾,亦即开始处理下一行
ba 是无条件跳转到标签a。省略标签a则到脚本末尾
十六 出现多次只保留一次
文件名:waitfordeal.sql
文件内容如下:
sp_addproc
sp_addproc
sp_delproc
sp_addproc
sp_addproc
sp_modproc
sp_delproc
sp_delproc
sp_modproc
sp_modproc
sp_modproc
sp_modproc
现在想得到存储过程名,出现多次只保留一次,即:
sp_addproc
sp_delproc
sp_modproc
不知道该怎么写命令啊?还请各位帮忙,谢谢!
文件内容如下:
sp_addproc
sp_addproc
sp_delproc
sp_addproc
sp_addproc
sp_modproc
sp_delproc
sp_delproc
sp_modproc
sp_modproc
sp_modproc
sp_modproc
现在想得到存储过程名,出现多次只保留一次,即:
sp_addproc
sp_delproc
sp_modproc
不知道该怎么写命令啊?还请各位帮忙,谢谢!
sort -u
awk '!($0 in a) {a[$0];print}'
awk '!a[$1]++' waitfordeal.sql
十七
怎么把下面语句括号里的逗号替换成别的符号?括号里面可能有一两个逗号,字段是不固定的.括号外逗号是做为分隔符,不想去掉.
$ cat sql24
'||CHAR(vYearMonth)
||',COOPR_NBR,COOPR_AREA_CD,CMCC_BRANCH_CD,SUBSTR(A_CMCC_BRANCH_CD,1,2),COOPR_BRND_CD,'
||'SUM(ACTVCALL_DUR),SUM(BYCALL_DUR),SUM(FORWARD_DUR),SUM(ACTVCALL_CNT),SUM(BYCALL_CNT),SUM(FORWARD_CNT),'
||' CASE WHEN VALUE(D.BRND_CD,1) IN (0,1) AND VALUE(C.CURRMO_CALC_FEE,0)>=0 AND VALUE(C.CURRMO_CALC_FEE,0)+VALUE(C.MON_FEE,0) >=5 THEN ''1'' '
||' WHEN VALUE(D.BRND_CD,1) IN (0,1) AND VALUE(C.CURRMO_CALC_FEE,0)<0 AND VALUE(C.MON_FEE,0)>=5 THEN ''1'' '
||' WHEN D.BRND_CD IN (2,3) AND VALUE(C.CURRMO_AMT_FEE,0) >=5 THEN ''1'' '
||' ELSE ''0'' END, '
||' CASE WHEN VALUE(C.CALLUSR_MOUNT,0) > 0 THEN ''0'' ELSE ''1'' END, C.PKG_CD, '
$ cat sql24
'||CHAR(vYearMonth)
||',COOPR_NBR,COOPR_AREA_CD,CMCC_BRANCH_CD,SUBSTR(A_CMCC_BRANCH_CD,1,2),COOPR_BRND_CD,'
||'SUM(ACTVCALL_DUR),SUM(BYCALL_DUR),SUM(FORWARD_DUR),SUM(ACTVCALL_CNT),SUM(BYCALL_CNT),SUM(FORWARD_CNT),'
||' CASE WHEN VALUE(D.BRND_CD,1) IN (0,1) AND VALUE(C.CURRMO_CALC_FEE,0)>=0 AND VALUE(C.CURRMO_CALC_FEE,0)+VALUE(C.MON_FEE,0) >=5 THEN ''1'' '
||' WHEN VALUE(D.BRND_CD,1) IN (0,1) AND VALUE(C.CURRMO_CALC_FEE,0)<0 AND VALUE(C.MON_FEE,0)>=5 THEN ''1'' '
||' WHEN D.BRND_CD IN (2,3) AND VALUE(C.CURRMO_AMT_FEE,0) >=5 THEN ''1'' '
||' ELSE ''0'' END, '
||' CASE WHEN VALUE(C.CALLUSR_MOUNT,0) > 0 THEN ''0'' ELSE ''1'' END, C.PKG_CD, '
sed ':a;s/\(([^)]*\),\([^)]*)\)/\1biedefuhao\2/;ta' sql24
十八 反转一行中每个字符的顺序
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
'/\n/!G'是判断本行是否有换行符,如果没有执行G命令
's/\(.\)\(.*\n\)/&\2\1/'命令是在原来行+第二个字符(或者没有)开始到换行符+第一个字符
//D命令是在模式空间删除第一行,注意执行完成后如果模式空间不为空,继续下一个循环执行.
'/\n/!G'是判断本行是否有换行符,如果没有执行G命令
's/\(.\)\(.*\n\)/&\2\1/'命令是在原来行+第二个字符(或者没有)开始到换行符+第一个字符
//D命令是在模式空间删除第一行,注意执行完成后如果模式空间不为空,继续下一个循环执行.
D命令删除模式空间第一个\n及之前的内容,并开始下一次循环,注意模式空间无内容时才开始处理下一行
G 把保存空间的内容附加到模式空间中去,保存空间的默认内容是空,执行后模式空间的内容会增加一个\n
s/.//命令是删除第一个字符
s/.//命令是删除第一个字符
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
###假设一行文字是 123
###那么执行后模式空间中的内容应该按下边的顺序变化
执行/\n/!G;得
123\n
然后s/\(.\)\(.*\n\)/&\2\1/;
得
123\n23\n1
执行//D
23\n1
因为是D命令所以从头循环
模式空间有\n
所以/\n/!G;中G不执行
再来s...
23\n3\n21
再D
3\n21
循环,G不执行
再来s...
3\n\n321
再D
\n321
循环
G和s和D都不执行
执行最后的s/.//
321
###假设一行文字是 123
###那么执行后模式空间中的内容应该按下边的顺序变化
执行/\n/!G;得
123\n
然后s/\(.\)\(.*\n\)/&\2\1/;
得
123\n23\n1
执行//D
23\n1
因为是D命令所以从头循环
模式空间有\n
所以/\n/!G;中G不执行
再来s...
23\n3\n21
再D
3\n21
循环,G不执行
再来s...
3\n\n321
再D
\n321
循环
G和s和D都不执行
执行最后的s/.//
321
十九 \( \)的理解
偶尔在一个shell脚本里面看到了一个类似sed 's/(\(.*\))/\1\1/'这样的语句,鉴于对shell不是非常熟悉,所以也就没有看懂,后来理解了一下,还算明白一二,贴出来理解过程,为与兄弟姐妹们交流。
其实这个sed替换就是针对含有括号的情况
比如下面会提到的
no1=100(AAA) no2=100(BBB) no3=100(CCC) no4=(DDD)
其中AAABBBCCCDDD都是变化的,我们要提取AAA或者BBB的情况
首先理解一个()的情况
举个例子:
[root@mail root]# echo "111(222)333"| sed 's/(\(.*\))/\1\1/'
111222222333
因为(\(.*\)只有这一个部分,所以\1就意味着这一个部分提取两次(如果是\2就应该提不到东西)
[root@mail root]# echo "111(222)333"| sed 's/(\(.*\))/\1\2/'
sed:-e 表达式 #1,字符 16:Invalid reference \2 on `s' command's RHS
由于(不是元字符,所以直接写(就表示(这个符号,而\(才表示包含什么的意思
而又因为是()里面的内容,所以将222提取两次
如果将()去掉,例如
[root@mail root]# echo "111(222)333"| sed 's/\(.*\)/\1\1/'
111(222)333111(222)333
那么提取的匹配就是这个部分了