1.shell中单引号和双引号的区别
至于 soft quote(双引号) 跟 hard quote(单引号) 的不同,主要是对于某些 meta 的关闭与否,以 $ 來作說明:
- $ A=B\ C
- $ echo "$A"
- B C
- $ echo '$A'
- $A
复制代码
在第一个 echo 命令行中,$ 被置于 soft quote 中,將不被关闭,因此继续处理变量替换,
因此 echo 將 A 的变量值输出到屏幕,也就得到 "B C" 的結果。
在第二个 echo 命令行中,$ 被置于 hard quote 中,則被关闭,因此 $ 只是一個 $ 符号,
并不会用來作变量替換处理,因此結果是 $ 符号后面接一个 A 字母:$A 。
2.如何去掉第2列的数字
[root@vshi-template shell]# more b.txt
1234567
213456
31345
4134
[root@vshi-template shell]# sed 's/.//2' b.txt
134567
23456
3345
434
说明:其中.表示任意1个字符或数字,2表示第2个位置,就是将第2个位置的1个任意字符或数字替换成空。
[root@vshi-template shell]# cut -b 1,3- b.txt
134567
23456
3345
434
说明:b表示字节,1表示第1个字节,3-表示获取从第3个字节到后面所有的字节。
[root@vshi-template shell]# awk -F '' -v OFS='' '{$2=""}1' b.txt
134567
23456
3345
434
说明:
3.设定变量file的值为/etc/passwd,依次向/etc/passwd中的每个用户问好,并且说出对方的ID是什么?
例如:Hello,root,your UID is 0.
-
for i in `awk -F : '{print $1","$3}' /etc/passwd`;do echo "Hello,${i%,*},your UID is ${i#*,}";done
-
awk -F: '{print $1,$3}' /etc/passwd|while read user uid; do echo "Hello,$user,you UID is $uid";done
说明:着重说明${i%,*}和${i#*,}的含义。
在经过awk -F : '{print $1","$3}' /etc/passwd处理后,用户和用户ID的格式会变成root,123这样。
#表示去掉左边 ##表示前贪婪匹配
%表示去掉右边 %%表示后贪婪匹配
单一符号是最小匹配,两个符号是最大匹配。
所以${i%,*}表示去掉最后1个,及其右边的字符,即剩下root
${i#*,} 表示去掉第1个,及其左边的字符,即剩下123
详细说明见:
例如:
[root@localhost ~]# echo ${MAIL}
/var/spool/mail/root
[root@localhost ~]# echo ${MAIL##/*/} #贪婪前匹配删除
root
[root@localhost ~]# echo ${MAIL#/*/} #前匹配删除
spool/mail/root
[root@localhost ~]# echo ${MAIL%/*} #后匹配删除
/var/spool/mail
[root@localhost ~]# echo ${MAIL%%/*} #贪婪后匹配删除
[root@localhost ~]# echo ${MAIL//oo/aa} #全局替换
/var/spaal/mail/raat
[root@localhost ~]# echo ${MAIL/oo/aa} #仅替换第一个
/var/spaal/mail/root
4.for循环的2个(())在什么时候会使用?
for ((i=1;i<=10;i++)); do echo $i; done
5.sed中\s和\S的含义
\s 匹配任意的空白符,等价于[\f\t\n\r ],其含5个空白字符:格式符(form-feed)、制表符(tab)、换行符、回车、空格符。
\S 匹配任意不是空白符的字符,是\s的补集
6. 关于2>&1和>&2的含义
find . -name "*.unl" -print >unl.txt 2>&1
将find查询到的结果和标准输出和标准错误都输入到文件unl.txt中;
find . -name "*.unl" -print >unl1.txt >&2
将find查询结果中的标准错误输入到文件unl1.txt中;
1>等同于>
1> 改变stdout的数据输出通道
2> 改变stderr的数据输出通过
2>&1 将stderr并进stdout做输出
1>&2 或 >&2 就是將 stdout 并进stderr 作输出
7.从shell向sed传值时,需要使用双引号,否则功能不执行。
8.关于变量的设置
(1)var=${str=expr}
当分别对str设置unset、null、not null这3种变量时的结果
showvar(){
var=${str=expr}
echo \$var is $var
echo \$str is $str
}
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar() {
-
> var=${str=expr}
-
> echo \$var is $var
-
> echo \$str is $str
-
> }
-
#删除str变量,即这个变量没有了,当系统中没有str这个变量时,系统就把expr复制为str,并显示str变量的值;
-
[mvno@ZSC-PC-DL580G7-2 shell]$ unset str
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is expr
-
$str is expr
-
#当设置str为null时,由于str变量存在,只是值为空,所以系统取的就是str的值,即null
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is
-
$str is
-
#当str的值非空时,系统取的就是非空的值
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is xyz
-
$str is xyz
(2)var=${str:=expr}
当分别对str设置unset、null、not null这3种变量时的结果;
其中冒号:表示为null
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar() {
-
> var=${str:=expr}
-
> echo \$var is $var
-
> echo \$str is $str
-
> }
-
-
[mvno@ZSC-PC-DL580G7-2 shell]$ unset str
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is expr
-
$str is expr
-
-
#无论变量str的值是null还是没有定义,都把expr的值赋值为str,并显示str变量的值;
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is expr
-
$str is expr
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is xyz
-
$str is xyz
通过上述测试,可发现当对str设置unset、not null时,这2种设置变量的方式,结果都是一样的;
只有null这种方式有所不同;后者会设置为expr.
--------------------------------------------------------
var=${str-expr}和var=${str:-expr}的区别
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar() {
-
> var=${str:-expr}
-
> echo \$var is $var
-
> echo \$str is $str
-
> }
-
[mvno@ZSC-PC-DL580G7-2 shell]$ unset str
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is expr
-
$str is
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is expr
-
$str is
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is xyz
-
$str is xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar() {
-
> var=${str-expr}
-
> echo \$var is $var
-
> echo \$str is $str
-
> }
-
[mvno@ZSC-PC-DL580G7-2 shell]$ unset str
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is expr
-
$str is
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is
-
$str is
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is xyz
-
$str is xyz
var=${str+expr}和var=${str:+expr}的区别
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar() {
-
> var=${str+expr}
-
> echo \$var is $var
-
> echo \$str is $str
-
> }
-
[mvno@ZSC-PC-DL580G7-2 shell]$ unset str
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is
-
$str is
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is expr
-
$str is
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is expr
-
$str is xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar() {
-
> var=${str:+expr}
-
> echo \$var is $var
-
> echo \$str is $str
-
> }
-
[mvno@ZSC-PC-DL580G7-2 shell]$ unset str
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is
-
$str is
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is
-
$str is
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is expr
-
$str is xyz
var=${str?expr}和var=${str:?expr}的区别
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar() {
-
> var=${str?expr}
-
> echo \$var is $var
-
> echo \$str is $str
-
> }
-
[mvno@ZSC-PC-DL580G7-2 shell]$ unset str
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
-bash: str: expr
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is
-
$str is
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is xyz
-
$str is xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar() {
-
> var=${str:?expr}
-
> echo \$var is $var
-
> echo \$str is $str
-
> }
-
[mvno@ZSC-PC-DL580G7-2 shell]$ unset str
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
-bash: str: expr
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
-bash: str: expr
-
[mvno@ZSC-PC-DL580G7-2 shell]$ str=xyz
-
[mvno@ZSC-PC-DL580G7-2 shell]$ showvar
-
$var is xyz
-
$str is xyz
变量设置方式
|
str没有设置
|
str为空字符
|
str已设置为非空字符
|
var=${str-expr}
|
var=expr
|
var=
|
var=$str
|
var=${str:-expr}
|
var=expr
|
var=expr
|
var=$str
|
var=${str+expr}
|
var=expr
|
var=expr
|
var=expr
|
var=${str:+expr}
|
var=expr
|
var=
|
var=expr
|
var=${str=expr}
|
var=expr
str=expr
|
str不变
var=
|
str不变
var=$str
|
var=${str:=expr}
|
var=expr
str=expr
|
var=expr
str=expr
|
str不变
var=$str
|
var=${str?expr}
|
expr输出至stderr
|
var=
|
var=$str
|
var=${str:?expr}
|
expr输出至stderr
|
expr输出至stderr
|
var=$str
|
9.关于$(())、${}、$()的区别
$()与``都是用来做命令替换用的;
${}用来做变量替换的;$var与${var}是一样的,只是${}能比较清晰的界定变量的范围;
$(())用来做整数运算的;
為了完整起見,我這裡再用一些例子加以說明 ${ } 的一些特异功能:
假設我們定义了一个变量為:
file=/dir1/dir2/dir3/my.file.txt
我們可以用 ${ } 分別替換获得不同的值:
${file#*/}:拿掉第一條 / 及其左边的字串:dir1/dir2/dir3/my.file.txt
${file##*/}:拿掉最後一條 / 及其左边的字串:my.file.txt
${file#*.}:拿掉第一個 . 及其左边的字串:file.txt
${file##*.}:拿掉最後一個 . 及其左边的字串:txt
${file%/*}:拿掉最後條 / 及其右边的字串:/dir1/dir2/dir3
${file%%/*}:拿掉第一條 / 及其右边的字串:(空值)
${file%.*}:拿掉最後一個 . 及其右边的字串:/dir1/dir2/dir3/my.file
${file%%.*}:拿掉第一個 . 及其右边的字串:/dir1/dir2/dir3/my
记忆的方法为:
# 是去掉左边(在键盘上 # 在 $ 之左邊)
% 是去掉右边(在键盘上 % 在 $ 之右邊)
单一符号是最小匹配﹔两个符号是最大匹配。
${file:0:5}:提取最左邊的 5 個字節:/dir1
${file:5:5}:提取第 5 個字節右邊的連續 5 個字節:/dir2
我們也可以對變量值裡的字串作替換:
${file/dir/path}:將第一個 dir 提換為 path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:將全部 dir 提換為 path:/path1/path2/path3/my.file.txt
利用 ${ } 還可針對不同的變數狀態賦值(沒設定、空值、非空值):
${file-my.file.txt} :假如 $file 沒有設定,則使用 my.file.txt 作傳回值。(空值及非空值時不作處理)
${file:-my.file.txt} :假如 $file 沒有設定或為空值,則使用 my.file.txt 作傳回值。 (非空值時不作處理)
${file+my.file.txt} :假如 $file 設為空值或非空值,均使用 my.file.txt 作傳回值。(沒設定時不作處理)
${file:+my.file.txt} :若 $file 為非空值,則使用 my.file.txt 作傳回值。 (沒設定及空值時不作處理)
${file=my.file.txt} :若 $file 沒設定,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt 。 (空值及非空值時不作處理)
${file:=my.file.txt} :若 $file 沒設定或為空值,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt 。 (非空值時不作處理)
${file?my.file.txt} :若 $file 沒設定,則將 my.file.txt 輸出至 STDERR。 (空值及非空值時不作處理)
${file:?my.file.txt} :若 $file 沒設定或為空值,則將 my.file.txt 輸出至 STDERR。 (非空值時不作處理)
上的理解在于, 你一定要分清楚 unset 和 null 及 non-null 这3种赋值状态.
一般而言, : 与 null 有关, 若不帶 : 的話, null 不受影响, 若帶 : 则连 null 也受影响.
还有哦,${#var} 可計算出变量值的長度:
${#file} 可得到 27 ,因為 /dir1/dir2/dir3/my.file.txt 刚好是 27个字节。
10. 数组
定义数组:A=(a b c def)
打印数组的所有元素:echo ${A[*]}或者echo ${A[@]}
打印第1个元素: echo ${A[0]}
打印数组中元素的数量:echo ${#A[@]}或者echo ${#A[*]}
打印第1个元素的长度:echo ${#A[0]}
重新定义第4个元素的值:A[3]=xyz
11.tee
tee的作用:读取标准输入的数据,并将其内容输出成文件
12. 关于break、exit、return
break 是結束 loop
return 是結束 function
exit 是結束 script/shell
13. stat命令可以比较详细的查询一个文件的信息
14.print和printf的区别
print无法使用%s、%d等,print打印换行
printf格式化函数,打印不换行
15.awk去除重复行
awk '!a[$0]++' 1.txt # !a[$0]++相当于!a[$0]&&a[$0]=a[$0]+1{print $0}
awk '!($0 in a){a[$0];print}' 1.txt
说明:
awk '!a[$0]++' file
一看之下,首先是想到又用到awk的hash,又是缺省的pattern,一下子来了兴趣,做了以下的分析
这个要从awk的执行模式开始说,最后结合++运算符,和hash特色
有三个基本知识点是要了解的
1:a++的作用是先附值,再累加a,与++a正好相反。
2:hash的初始是undef,通过直接附值或声明进行定义,如a[1]=1,或直接声明a[1]。
3:awk的基本模式是,pattern { action statements },action部分是可以省略的,缺省情况下是输出,即{print $0},至于pattern可以理解成是表达式,通过pattern表达式的值的真假,来确定是否要进行action。比如1,最简单的awk用来实现cat的功能就是 awk '1',这边1就是pattern,当然,1也可以是2,3,4,5等其他数字,但如果用字母的话,就不行,因为字母会解释成变量,变量初始值未定义,初始值为假,或者可以加个!反义
结合上边三点来分析awk '!a[$0]++' file
"!a[$0]++"
0:整个模式,没有用到action,所以采用的是默认的{print $0},即在patten为真条件来,输出行
patten分析:
1:使用了一个hash数组,a,数组的键值采用$0,即每行值
2:当a[$0]未声明时,a[$0]为假,在未声明的情况下,进行一次a[$0]++后,a[$0]即为真
3:!取反
结论:当相同的行第一次读入时,pattern为真,行输出,再次读入后,patten为假,行乎略
基本理论知道了,要用得出来还得多锻炼应用
上周帮别人写个awk,也是这种情况,我写的
awk '{if($2 in a);else{a[$2]=$0}}END{for(b in a)print a[b]}' urrfile
后来别人给出更简单的答案
awk ' !($2 in i){ i[$2]; print } ' urrfile
现在看来,还可以更简单些
awk '!a[$2]++' urrfile
【注意】:这是前加/后加的区别,前几天还说过。
后加: 先使用变量的值,再自加。
!a[$0]++ 对这个表达式的求值,它的值与 !a[$0] 相同(先使用变量a[$0]的值),但对表达式求值后 a[$0]会自加。
16.现在有个文件1.txt,每行1个uid;使用awk进程处理1行,要10个uid且要用逗号分隔
more 1.txt
154891
145690
165211
190189
135901
290134
190189
135901
290134
190189
135901
290134
处理后的结果为:
154891,145690,165211,190189,135901,290134,145690,165211,190189,135901
290134 ,145690,165211,190189,135901,290134 ,
方法1:awk 'ORS=NR%10?",":"\n"' 1.txt
说明:本例是通过修改输出记录分隔符,用了三元操作符?A:B
当输出的行号除以10取余为0时,那么赋值ORS为\n
当输出的行号除以10取余为非0时,那么赋值ORS为,
也可写成awk 'if(NR%10){ORS=","}else{ORS="\n"}' 1.txt
方法2:awk '(NR%10){print;next}{printf $0","}' 1.txt
原理同上,当NR%10取余为0时,跳过该行,当NR%10为非0时,打印它并在后加,
方法3:awk '{if(NR%10){ORS=",";printf $0","}else{ORS="\n";print $0}}' 1.txt
该方法是方法1的变形;
17. 创建数组
[mvno@ZSC-PC-DL580G7-2 shell]$ m=(`echo 192.168.1.{136..140},12`)
[mvno@ZSC-PC-DL580G7-2 shell]$ echo ${m[*]}
192.168.1.136,12 192.168.1.137,12 192.168.1.138,12 192.168.1.139,12 192.168.1.140,12
18.awk中如何区分pattern和action?
凡是被{}包裹的就是action,或者说action必然被{}包裹着;
凡是没有被{}包裹的就是pattern,或者说pattern不能被{}包裹着。
可做pattern的几种情况:
(1)正则表达式做pattern;
awk '/555-5553/ {print $0}' myfile
(2)比较表达式做pattern.
awk '$NF=="A" {print $0}' myfile
(3)常量做pattern
pattern匹配,共有2种情况:要么匹配,就执行后面的action;要么不匹配,就不执行后面的action;
什么东西能作为常量呢?一个数字、一个字符串都可作为常量。这里有一个龟腚了:
凡是非0的数字,就表示pattern匹配成功,也就是pattern为真,否则表示匹配失败,就为假;
凡是非空的字符集,就表示pattern匹配成功,也就是pattern为真,否则表示匹配失败,就为假;
注意:字符串是由引号引起来的,0和‘0’是不一样的,数字0为假,字符串‘0’为真(不为空)
(4)空pattern
awk ‘{print $0}’myfile
这里没有pattern,空的。那么就表示匹配输入记录永远成功,也就是说永远为真,这是龟腚,action永远都会执行!
pattern可省略,当然action也能省略,省略后的话,默认为{print $0};
具体可参见:
(5)特殊的pattern:BEGIN,END
在awk中,经常遇到BEGIN、END这2个玩意儿,例如:awk ‘BEGIN{...}END{...}’
实际上,BEGIN和END只是两个特殊的pattern,类似的还有BEGINFILE,ENDFILE.
BEGIN在读入文件之前匹配成功,即在读入文件之前这条rule就已经执行了.
END在处理完文件之后才匹配成功,即在处理完文件之后才会执行这条rule.
(6)模式范围:begpat、endpat
这个模式范围,是由两个pattern组成,每个pattern可以是任意的非特殊类型(非BEGIN/END模式类型)的pattern类型(可以是
正则,比较,常量等pattern)
这个模式范围匹配的规则有点特殊,这里以一个“开闸放水”的例子作为一个类比;
1.首先以第一个pattern匹配输入记录,如果第一个pattern匹配成功,就“打开放水的开关开始放水”,[开关的状态:开],即
会立即执行后面的action,此时不管第二个pattern是否匹配;
2.接着再匹配第二个pattern,如果第二个pattern匹配失败,开关的状态不变,即还是会执行action;
3.接着继续以第二个pattern匹配下一条输入记录,直到第二个pattern匹配成功,就“关闭放水的开关停止放水”,
[开关的状态:关],模式范围匹配结束;
4.以1/2/3步骤进入下一轮模式范围匹配.
阅读(1191) | 评论(0) | 转发(0) |