第一章 小试牛刀
echo 后面可以直接跟内容,或者用单引号和双引号
1.单引号中的变量不会被解析,比如echo '$aa' 结构就是 $aa
2.不带引号时,echo hello;hello 的第二个hello会被当做命令执行
echo -n 忽略换行 echo -e 输出的内容会被转移
printf
%-5s 打印字符串,- 表示左对齐,不到5位的用空格替代 $s格式化字符串,%c是替换字符,%d是数字,%f是浮点数
输出带色彩的文件和背景
echo -e "\e[1;45m \e[1;31m sssssssssssssss \e[0m"
变量的一些简单实用
var=hello 输出var变量 echo $var echo ${var} 求字符串长度 echo ${#var} 当前的shell版本 echo $SHELL echo $0
数学运算
let var++ #执行let时候变量前面不需要加$符号 echo $var result=$[no1 + no2] #[]中也可以使用$前缀 result=$[$no1 + 5] result=$(( no1 + 5 )) #()这种写法时,变量前必须加上$ echo "4*3.14" | bc #只有bc才支持浮点运算
调用一个shell有两种方式,调用一个shell执行然后得到它的返回值
result=`expr 3+4` result=$(exprt $no1+5)
输入输出
0 stdin(标准输入) 1 stdout(标志输出) 2 stderr(标志错误) > 等同于1>; >>等同于1>> echo "hello " 2>&1 out.log echo "hello" &> out.log
自定义文件描述符(注意 > 符号和数字之间不能有空格)
echo "this is new line" > input.txt exec 3<input.txt cat <&3 exec 4 > out.txt echo "new line" >& 4 exec 5>>input.txt echo "append" >&5 echo "aaa" 2> /dev/null #错误输出重定向到黑洞文件
数组
array_var=(1,2,3,4,5,6) array_var[0]="test1" array_var[1]="test2" array_var[2]="test3" echo $(array_var[0]) echo $(array_var[$index]) #假设index=5 echo $(array_var[@]) 结果: test1 test2 test3 test4 test5 test6 echo $(#array_var[*]) #打印数组长度
关联数组
declare -A ass_array ass_array=(([index1]=val-1 [index2]=val-2)) 或者: ass_array[index1]=val-1 ass_array[index2]=val-2 fruits_value=( [apple]='100 dollars' [orage]='150 dollars' ) 列出数组索引 echo $(!array_var[*]) echo $(!array_var[@]) 语法 描述 ${!array[*]} 取关联数组所有键 ${!array[@]} 取关联数组所有键 ${array[*]} 取关联数组所有值 ${array[@]} 取关联数组所有值 ${#array[*]} 关联数组的长度 ${#array[@]} 关联数组的长度
别名
alias rm='cp $@ ~/backup; rm $@' 可以将其放入到 ~/.bashrc文件中,新的shell进程就会生效,删除可以从这个文件中删除或者使用 unalias命令
时间
sleep 秒 usleep 微妙(百万分之一秒) date,格式化字符串 星期 %a(简写) %A(完整) 月 %b(简写) %B(完整) 日 %d 年 %y(两位表示) %Y(四位表示) 小时 %H 分钟 %M 秒 %S 纳秒 %N 时间戳 %s
调试
sh -x script.sh set -x: 在执行时显示参数和命令 set +x: 禁止调试 set -v: 当命令进行读取时显示输入 set +v: 禁止打印输入 function DEBUG() { [ "$_DEBUG" == "on" ] && $@ || : } 可以将调试功能设置为on来运行脚本 _DEBUG=ON ./scritp.sh DEBUG函数中的 : 告诉shell不要执行任何操作 把 #! /bin/bash 改成 #! /bin/bash -xv 这样不用其他任何选项就可以启用调试功能了
函数
调用函数方式 myfun ; 传递参数 myfun arg1 arg2 ; 参数可以传递给脚本并通过$0(脚本名) 访问 $1 第一个参数 $2 第二个参数 $n 第n个参数 $@ 被扩展成 "$1" "$2" "$3" 等 $* 被扩展成 "$1c$2c$3"等 $@用的最多,由于$*将所有参数当做单个字符串因此很少被使用 导出函数,之后函数的作用域就可以扩展到子进程中 export -f myfun 读取命令返回值(状态) cmd; echo $? 利用()可以生成子shell,子shell中执行的内容不会对父shell产生影响 pwd; (cd /bin; ls)
从控制台读取
read -n number_of_chars variable_name #从输入中读取n个字符并存入变量variable_name中 read -s var #用不回显的方式去读密码 read -p "enter input :" var # 显示提示信息 read -t timeout var #在特定的时间内读取输入read -t 2 var 两秒内输入 read -d delim_char var #用定界符结束输入行 read -d ":" var #输入hello: var被设置为hello
分隔符
读取/etc/passwd,打印出用户默认的shell line="root:x:0:0:root:/root:/bin/bash" oldIFS=$IFS IFS=":" count=0 for item in $line; do [ $count -eq 0 ] && user=$item; [ $count -eq 6 ] && shell=$item; let count++ done; IFS=$oldIFS echo $user\'s shell is $shell 结果: root's shell is /bin/bash echo {1..50} #能够生产从1到50的数字列表 echo {a..z}或者{A..Z},或者使用{a..h}生产部分列表 for i in {a..z} do action; done; for循环 for var in list; do command; done 采用c语言中的for循环格式 for((i=0;i<10;i++)) { commands; } while循环 while condition do command; done 用true作为循环条件能够参数无限循环 until循环(它会一直执行循环直到给定的条件为真) x=0; unitl [ $x -eq 9 ]; do let x++; echo $x; done
比较
if condition;then commands; fi if condtion;then commands; elif condtion;then commands; else commands; fi 条件通常被放置在封闭的中括号内,一定要注意在[或]与操作数之间有一个空格,如果忘记空格脚本就 会报错 一些重要的操作符: -gt 大于 -lt 小于 -ge 大于或等于 -le 小于或等于 -eq 等于 -nq 不等于 文件系统相关测试 [ -f $file_var ] 如果给定的变量包含正常的文件路径或文件名则返回真 [ -x $var ] 如果给定的变量包含的文件可执行,则返回真 [ -d $var ] 如果给定的变量包含的是目录,则返回真 [ -e $var ] 如果给定的变量包含的文件存在,则返回真 [ -c $var ] 如果给定的变量包含的是一个字符设备文件的路径,则返回真 [ -b $var ] 如果给定的变量包含的是一个块设备文件的路径,则返回真 [ -w $var ] 如果给定的变量包含的文件可写,则返回真 [ -r $var ] 如果给定的变量包含的文件可读,则返回真 [ -L $var ] 如果给定的变量包含的是一个符号链接,则返回真 字符串比较(因为有时候采用单个中括号会产生错误,最好使用双个中括号) 注意在 = 前后各有一个空格,如果忘记加空格,那就不是比较关系了,而变成赋值语句了 [[ $str1 = $str2 ] [[ $str1 == $str2 ] [[ $str1 != $str2 ] [[ $str1 > $str2 ] #str1的字母序比str2大 [[ $str1 < $str2 ] [[ -z $str1 ]] #如果str1包含的是空字符串,则返回真 [[ -n $str1 ]] #如果str1包含的是空字符串,则返回真
第二章 命令之乐
cat相关
cat file1 file2 file3 #将多个文本内容拼接在一起 OUTPUT_FROM_SOME COMMANDS | cat #从表中输入中读取 echo 'from stdin' | cat - file.txt cat -s file #压缩空白行 cat -T file.py #将制表符显示为 ^| cat -n file.txt #显示行号
录制和回放终端会话
script scriptreplay
文件查找
find base_path #base_path 可以是任何位置 -print 指明打印出匹配的文件名(路径) -print0 指明使用'\0'作为定界符来打印每一个匹配的文件名 -name 后面的参数可以包含正则表达式,指定了文件名所必须匹配的字符串 -iname 类似-name,但是忽略大小写,如果有多个匹配条件可以用OR,也可以用!否定参数的含义 find . \(-name "*.txt" -o -name "*.pdf" \) -print find . ! -name "*.txt" -print #打印所有不以.txt结尾的文件 -regex 支持正则表达式 -iregix 忽略大小写 find . -iregex ".*\(\.py\|\.sh\)$" #忽略大小写找到所有py和sh结尾的文件 -maxdepth 深度搜索,最多搜索多少层 -mindepth 深度搜索,最少搜索多少层 find . -maxdepth 1 -type f -print #从性能角度来说,最好先指定深度再确定类型 -type 搜索文件类型 普通文件 f 符号链接 l 目录 d 字符设备 c 块设备 b 套接字 s fifo p -atime 用户最近一次访问文件的时间,可以带上 + 和 - 表示大于和小于 -mtime 文件内存最后一次被修改的时间 -ctime 文件元数据(metadata,列如权限 或所有权)最后一次改变的时间 find . -type f -atime -7 print #打印出最近七天内被访问过的所有文件 find . -type f -atime 7 print #打印出恰好在七天前被访问过的文件 find . -type f -atime +7 print #大餐饮出访问时间超过七天的所有文件 -amin 访问时间,以分钟为单位 -mmin 修改时间,以分钟为单位 -cmin 变化时间,以分钟为单位 find . -type f amin +7 -print #打印出访问时间超过7分钟的所有文件 -newer 指定一个用户比较时间长的参考文件,然后找出比参考文件更新的(更长修改时间)文件 find . -tpe f -newer file.txt -print -size 根据文件大小搜索 b 块(512字节) c 字节 w 字(2字节) k 千字节 M 兆字节 G 吉字节 find . -type f -size +2k #大于2k的文件 -delete 用来删除find查找到的匹配文件 find . -type f -name "*.swp" -delete #删除当前目录下所有.swp文件 -perm 根据文件权限和所有权查找(-user 可以指定用户) find . -type f -perm 644 -print #打印出权限位644的文件 find . -type f -user testuser -print #打印出所有testuser用户的文件 -prune 跳过指定的目录 find /data0/source_path \( -name ".git" -prune \) -o \( -type f -print \) #忽略git文件 -exec 可以与其他命令结合(但是只能执行一个命令) find . -type f -user root -exec chown testuser {} \; #上面的语句是找到所有root所有者的文件修改为testuser,对于每一个匹配的文件{}会被替换成 #相应的文件名,如果找到两个文件file1.txt和file2.txt那么会执行 chown testuser file1.txt chown testuser file2.txt find . -type f -name "*.c" -exec cat {} \;>all_c_files.txt #上面的命令是将所有c程序文件拼接起来写入单个文件all_c_files find . -type f -mtime +10 -name "*.txt" -exec cp {} OLD \; #上面的命令将10天前的.txt文件复制到OLD目录中 find . -type f -exec ./commands.sh {} \; #虽然-exec 参数无法使用多个命令,但是可以执行一个脚本,在脚本中放入多个命令 find . -type f -name "*.txt" -exec printf "Text file : %s\n" {} \; #-exec能够同printf结合起来生产有用的输出信息
玩转xargs
xargs命令把从stdin接收到的数据重新格式化,再将其作为参数提供给其他命令 -n 参数表示将输入的内容转换为指定的行 cat example.txt | xargs -n 3 #将example.txt的内容转换为3行 -d作为定界符 echo "splitXsplitXsplitXsplit" | xargs -d X -n 2 #结果: split split split split 假设args.txt内容如下: arg1 arg2 arg3 -I选项指定一个替换字符串,这个字符串在xargs扩展时会被替换掉。当-I与xargs结合使用时, 对于每一个参数,命令都会被执行一次 cat args.txt | xargs -I {} ./echo.sh -p {} -x 结果为: ./echo.sh -p arg1 -x ./echo.sh -p arg2 -x ./echo.sh -p arg3 -x
用tr进行转换
tr 输入部分 [需要转换的部分] [转换后的部分] echo "hello world hehe 1234 aa" | tr 'a-z' 'A-Z' #结果: HELLO WORLD HEHE 1234 AA 压缩字符 echo "gun is not unix " | tr -s ' ' #将连续的字符压缩成单个字符 删除 echo "hello world hehe 1234 aa" | tr -d '0-9' #结果: hello world hehe aa 补集,比如下面这个列子,将不在 0-9,空格,回车中的字符全部删除 echo hello 1 char 2 next 4 | tr -d -c '0-9 \n' #结果: 1 2 4
校验和核实
md5sum file #创建一个文件的指纹,并将字符串打印到控制台上 md5sum file > check.md5 #生成的内容 65466125197978378ec6340989ac50db check.log md5sum -c check.md5 #对文件进行校验 sha1sum file #创建一个文件的指纹,并将字符串打印到控制台上 sha1sum file > check.sha1 #生成的内容 3acec0d3b6e19f68c4d25de104eabb25d5c982d2 checkfile.log sha1sum -c check.sha1 #对文件进行校验
排序
sort -n 按数字进行排序 sort -r 逆序排序 sort -M 按照月份排序,一月,二月,三月这样的顺序 sort -C 测试一个文件是否已经被排序过 sort -m sorted1 sorted2 合并两个排序过的文件,而且不需要对合并后的文件再进行排序 sort -k 指定了排序应该按照哪一个键来排序 sort -b 忽略文件中的前导空白字符 sort -d 按照字典排序 sort -o file.log 将排序结果输出到指定文件中 sort -u 文件去重 #用法 sort -C file if [ $? -eq 0 ];then echo sorted else echo unsorted fi
单一与重复
uniq命令可以消除重复的内容,但必须用于排序过的数据,一般和sort命令结合使用 uniq -u sorted.txt 只显示唯一的行(在输入文本中没有出现重复的行) uniq -c sorted.txt 统计各行在文件中出现的次数 uniq -s 2 sorted.txt 指定可以跳过前N个字符 uniq -w 2 sorted.txt 指定用于比较的最大字符串 uniq -z file.txt 为每行最后添加\0值字符
临时文件与随机数
echo $RANDOM #每次都会返回一个随机数 temp_file="/tmp/file-$RANDOM" tmpe_file="/tmp/var.$$" # $$表示当前进程的id
文件分割
split -b 10k data.file ls #结果为: data.file xxa xab xac ... axj xa开头的一共10个文件 split -d 指定数字为后缀 split -a 4 指定后缀长度 split -b 10k data.file -d -a 4 split [command_args] prefix 分割的文件前缀
根据扩展名切分文件名
file_jpg="sample.jpg" echo ${file_jpg%.*} #输出sample echo ${file_jpg#*.} #输出jpg ${VAR%.*} 表示删除位于%右侧的通配符(也就是 .* ),通配符从右向左进行匹配 这种是非贪婪形的 ${VAR%%.*} 从右向左执行贪婪操作匹配 file=hack.fun.book.txt ${file%%.*} 输出为hack ${VAR#*.} 是从左向右匹配,删除位于#右侧的通配符(也就是 *. ) ${VAR##*.} 是贪婪匹配,从左向右删除变量中匹配的结果 file=hack.fun.book.txt ${file##*.} 结果是txt
批量重命名和移动
count=1; for img in *.jpg *.png do new=image-$count.${img##*.} mv "$img" "$new" 2> /dev/null if [ $? -eq 0 ];then echo "renaming $img to $new" let count++ fi done
第三章 以文件之名
生成任意大小的文件
dd if=/dev/zero of=/junk.data bs=1M count=1 if是input file of是output file bs是block size count代表需要被复制的块数 块的大小定义如下: 字节(1B) c 字(2B) w 块(512B) b 1k k 1m M 1g G
文件的交集与差集
cat a.log apple gold iron orange silver steel cat b.txt carrot cookies gold orange comm a.log b.log 结果: apple carrot cookies gold iron orange silver steel 第一列是只在a.log中出现的 第二列是只在b.log中出现的 第三列是同时在a.log和b.log中出现的 comm a.log b.log -1 #删除第一列 comm a.log b.log -2 #删除第一列 comm a.log b.log -3 #删除第一列 comm a.log b.log -1 -2 #删除第一和第二列
查找并删除重复文件
#! /bin/bash ls -lS | awk 'BEGIN{ getline;getline size=$5; lastName=$9 } { currentName=$9 if(size==$5) { "md5sum "lastName | getline; csum1=$1; "md5sum "currentName | getline; csum2=$1; if(csum1==csum2) { print lastName print currentName } }; size=$5 lastName=currentName } ' | sort -u > dup_file cat dup_file | xargs -I {} md5sum {} | sort | uniq -w 32 | awk '{ print $2 }' | sort -u > dup_sample_file comm dup_file dup_sample_file -2 -3 | tee /dev/stderr | xargs rm #首先获得文件列表然后遍历并按大小排序,获取文件大小和文件名,如果文件大小相同再比较两个文件 #的MD5值。如果MD5值相同那么肯定是重复的文件,把这两个文件名打印出来,最后重定向到dup_file中 #之后cat这个文件再对每行(也就是每个重复的文件)计算MD5值并排序(只比较前32个字节),最后去重 #只打印一个重复的文件并重定向到dup_sample_file中 #最后用comm比较dup_file和dup_sample_file,打印出只在dup_file中出现的文件,并用tee打印到标准 #错误输出中,最后交给xargs 删除这些文件 #其中上面的功能只需要一行就可以完成了 ll | awk 'BEGIN{getline} {print $9}' | xargs -I {} md5sum {} | uniq -w 32 -D | awk 'BEGIN{getline}{print $2}' | xargs -I {} rm {} #awk中的getline是读取一行,ll的第一行内容不需要所以只读取然后忽略即可,之后用对每个文件做 #MD5,然后比较前32个字节,打印出所有重复的文件名,之后再用awk,忽略掉第一行(从第二行开始读) #然后交给xargs最后删除这些重复文件
文件权限 所有者和粘滞位
ls的第一位 - 普通文件 d 目录 c 字符设备 b 块设备 l 符号链接 s 套接字 p 管道 之后是9个权限位rwxrwxrwx,用户,组,其他 对于用户来说有一个suid位,-rwS------ setuid权限允许用户以其他拥有者的权限来执行可执行文件 对于组用户有一个sgid位,----rwS--- setgid位允许以同该目录拥有者所在组相同 的有效组权限来执行文件 目录有一个特殊权限,叫粘滞位。当一个目录设置了粘滞位,只有创建该目录的用户才能删除目录中的文件,即使其他用户和组用户有权限也不行。 粘滞位出现在其他用户执行的执行权限位置(x),使用t或者T表示,如果没有设置执行权限,但设置了粘滞位则使用t表示;如果同时设置了执行权限和粘滞位就使用T表示 chmod a+t directory_name #设置粘滞位 chmod 777 . -R #递归执行 chmod +s executeable_file #设置sid位
批量生成空文件 创建不可修改文件
touch file for name in {1..100}.txt do touch name done touch -a 只更改改文件的访问时间(access time) touch -m 只更改文件内容修改时间(modification time) touch -d 为文件指定特定的时间戳 touch -d "Jan 20 2010" chattr -i file #设置不可删除的文件
查找符号链接及指向
ll | grep "^l" | awk '{print $9 " " $10 " " $11}' find -type l | xargs readlink
列举文件类型统计信息
#遍历一个目录下的文件类型,并打印出这种文件类型出现的次数 #下面这段代码是书中提供的,但是有问题不知道如何修改 #! /bin/bash if [ $# -ne 1 ];then echo $0 bashpath; echo fi path=$1 declare statArray find $path -maxdepth 1 -print | while read line do ftype=`file -b $line` let "statArray[$ftype]"++ ; done for ftype in "${!statArray[@]}" do echo $ftype : ${statArray["$ftype"]} done #上面的功能用一行就看以完成了 find /root -maxdepth 1 -print | xargs -I {} file -b {} | awk '{sum[$0]++} END{ for(i in sum){print i "\t" sum[i]} }'
环回文件与挂载
dd if=/dev/zero of=loopback.img bs=10m count=1 mkfs.ext3 loopback.img sudo mkdir /mnt/loopback mount -o loop lopback.img /mnt/loopback mount -t ext4 /dev/sdb1 /data1 #挂载一个分区
文件补丁
diff version1.txt version2.txt #显示差异 #-u用做生成一体化输出,并将结果重定向到patch文件中 diff -u version1.txt version2.txt > version.patch #给version1打补丁后就变成了version.txt patch -p1 version1.txt < version.patch #再打一次补丁就还原回version1了,此时会出现是提示,是否需要继续执行 patch -p1 version1.txt < version.patch
head和tail
head file #默认打印前10行 head -n 5 file #打印前5行 head -n -5 file #打印除了最后5行外的所有行 tail file #打印最后10行 tail -n 5 file #打印最后5行 tail -n +5 file #打印除了前5行外的所有行 seq 100 | tail -n +20 #seq 100 会打印出1到100个数字,每打印一次会换行 dmegs | tail -f PID=${pidof Foo} tail -f file --pid $PID #当进程Foo结束后,tail也会跟着结束
只列出目录
ls -D ls -F #对于目录会增加/ 结尾,对于文件增加 * 结尾 ls -F /home | grep "/$" #查找/home目录的所有文件,以/ 结尾的 ls -l /home | grep "^d" find /home -type d -maxdepth 1 -print
在命令行中用pushd和popd快速定位
pushd可以在多个目录中快速的定位 pushd /data0/test/mydir pushd /home/hehe/test pushd /var/log/test pushd /test/dir 位置从0开始 dirs /test/dir /var/log/test /home/hehe/test /data0/test/mydir pushd +0 就是/test/dir表示在这个目录不动 pushd +1 就是切换到/var/log/test popd 是弹出最上面的目录 popd +n 弹出第n个目录,它也是从下标0开始计算的 popd +1 表示弹出/var/log/test 如果只有两个目录/data0/test和/home/hehe 先cd到/data0/test再cd到/home/hehe 如果想切回到/data0/test 执行cd - 即可,再切换到/home/hehe,再执行一次 cd - 不停的执行cd - 就可以在两个目录之间切换了
统计文件的行数 单词数和字符数
wc -l file #统计行数 wc -w file #统计单词数 wc -c file #统计字符数 wc file #打印出文件的行数,单词数和字符数 wc file -L #打印最长行的长度
打印目录树
tree tree -P "*.jpg" #用通配符描述样式 tree -L [path] #指定递归的目录深度 tree --inodes #列出文件并显示这个文件的inode tree -d [path] #只显示目录 tree -s [path] #列出文件并显示大小(字节) tree -D [path] #列出文件并显示修改时间 tree -H [path] #以HTML格式打印 tree -o file [path] #结果重定向到文件中
第四章 让文本飞
正则表达式
^ 行起始标记 ^tux 匹配以tux起始的行 $ 行尾标记 tux$ 匹配以tux结尾的行 . 匹配任意一个字符 Hack.匹配Hack1和Hacki,但是不匹配Hackl2和Hackil [] 包含在[]之中任意字符 cook[kl]匹配cook或cool [^] 匹配除^之外任意字符 9[^01]匹配92,93但是不匹配91或90 [-] 匹配[]中指定范围任意字符 [1-5]匹配从1~5的任意一个数字s ? 匹配之前的项1次或0次 colou?r 匹配color或者colour,但不能匹配colouur + 匹配之前的项目1次或多次 Rollno-9+ 匹配Rollno-99,Rollno-9 * 匹配之前的项0次或多次 co*l匹配cl,col,coool等 () 创建一个用于匹配的字串 ma(tri)? 匹配max或maxtrix {n} 之前的项匹配n次 [0-9]{3}匹配任意一个三位数,[0-9][0-9][0-9] {n,m} 指定之前的项所必须匹配的最小和最大次数 [0-9]{2,5}匹配从两位数到五位数之间任意一个 | 交替--匹配 | 两边任意一项 Oct(1st|2nd) 匹配Oct1st或0ct2nd \ 转移符可以将特殊字符进行转移 a\.b匹配a.b \b 单词边界 \bcool\b 匹配cool,但不匹配coolant \B 非单词边界 cool\B 匹配coolant,但不匹配cool \d 单个数字字符 b\db匹配b2b,但不匹配bcb \D 单个非数字字符 b/Db匹配bcb,但不匹配b2b \W 单个单词字符(字母数字下划线) \w匹配1或a,但不匹配& \W 单个非单词字符 \W匹配&,但不匹配1或a \n 换行符 \n匹配一个新行 \s 单个空白字符 X\sx匹配x x,但不匹配xx \S 单个非空白字符 x\Sx匹配xx,但不匹配x x \r 回车 匹配回车 #匹配一个IP地址 [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.
用grep搜索
grep match_pattern filename grep "match_pattern" filename echo -e "this is a wordl\ntext line" | grep word grep "match_text" file1 file2 file3 ... #对多个文本进行搜索 grep word filename --color=auto #对输出行中重点标记处匹配到的单词 grep -E "[a-z]+" #使用扩展正则表达式 egrep "[a-z]+" #功能同上 grep -v "match_pattern" file #打印除包含match_pattern的行之外的所有行 grep -c "text" filename #统计文本或文件中包含匹配字符串的行 echo -e "1 2 3 4\nhello\n 5 6" | egrep -c "[0-9]" #统计匹配的行的数量,不是次数 grep linux -n sample.txt #打印出包含匹配字符串的行数 echo gnu is not unix | grep -b -o "not" #打印样式匹配所位于的字符或字节偏移 #结果 7:not grep "text" . -R -n #在多级目录中对文本进行递归搜索 . 指定了当前的目录 echo "hello world" | grep -i "HELLO" #忽略大小写 grep -e "pattern1" -e "pattern2" #匹配多个样式 grep -f pattern_file filename #用-f读取一个匹配样式文件 grep "main()" . -r --include *.{c,cpp} #在目录中只递归搜索.c和.cpp文件 grep "main()" . -r --exclude "README" #在搜索中排除搜油的README文件 grep --exclude-dir #排除目录 grep --exclude-from FILE #排除所需的文件列表 grep -q #静默输出,可以用于 if [ $? -eq 0 ]; 来判断 seq 10 | grep 5 -A 3 #打印某个匹配结果之后的3行 seq 10 | grep 5 -B 3 #打印某个匹配结果之前的3行 seq 10 | grep 5 -C 3 #打印某个结果之以及之后的3行
用cut按列切分文件
cut -f FIELD_LIST filename cut -f 2,3 filename #默认按照空格分隔,读取第二第三列 cut -d ";" #指定定界符 cut -c 1-5 range_file.txt #打印第一到第五个字符 cut -f #表示定义字符安 cut -b #表示定义字节
统计特定文件中的词频
egrep -o "[a-zA-Z]+" $filename | awk '{count[$0]} END{printf("%14s%s\n", "WORD", "COUNT")} for(ind in count){printf("%-14s%d\n",ind,count[ind])} '
sed入门
sed 's/pattern/replace_string/' file #替换 sed -i 's/pattern/replace/' file #使用-i,可以替换原文件 sed 's/pattern/replace/g' file #替换所有处 sed '/pattern/p' #打印匹配的内容 echo this thisthisthis | sed 's/this/THIS/2g' #从第N+1处开始替换 #this THISTHISTHIS echo this this this this | sed 's/this/THIS/3g' #this this THIS THIS echo this this this this | sed 's/this/THIS/4g' #this this this THIS #移除空白行 sed '/^$/d' # d 是删除 echo this is an example | sed 's/\w\+[&]/g' #用 & 标记匹配样式的字符串 [this] [is] [an] [example] #能够在匹配字符串时使用已匹配的内容 echo this is digit 7 in a number | sed 's/digit\([0-9]\)/\1/' #上面这个命令将digit 7替换为7,\(pattern\) 用于匹配子串,对于匹配的第一个子串对应的标记是 # \1,匹配的第二个子串是\2,下面是包含了多个匹配 echo seven EIGHT | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1' # EIGHT seven
awk入门
awk脚本的基本结构 awk 'BEGIN{ command } pattern{commands} END{ command }' file echo | awk '{var1="v1"; var2="v2"; var3="v3"; print var1,var2,var3}' #结果v1 v2 v3 #print var1"-"var2"-"var3 #结果v1-v2-v3 #特殊变量 NR 表示记录数量,相当于行号 NF 表示字段数量,在执行过程中对应当前的字段数 $0 当前行的文本内容 $1 第一个字段的文本内容 $2 第二个字段的文本内容 VAR=1000 echo | awk -v VARIABLE=$VAR '{print VARIABLE}' #将外部变量的值传给awk 用getline读取行 seq 5 | awk 'BEGIN{ getline; print "read ahead first line", $0} {print $0}' #read ahead first line 1 awk 'NR < 5' #行号小于5的行 awk 'NR==1,NR==4' #行号在1到5之间的行 awk '/linux/' #包含样式linux的行 awk '!/linux/' #不包含样式linux的行 awk -F ":" '{print $NF}' file #重新设置定界符 awk 'BEGIN{FS=":"}' #同上 "command" | getline output #将command的输出读入变量output中 echo | awk '{"grep root /etc/passwd" | getline out; print out}' #结果 root:x:0:0:root/root:/bin/bash #在awk中使用循环 for(i=0;i<10;i++) {print $i} for(i in array) {print array[i]} #内建字符串 length(string) #返回字符串的长度 index(string,search_string) #返回search_string在字符串中出现的位置 split(string,array,delimiter) #用定界符生成一个字符串列表,并将结果存入数组 substr(string,star-position,end-position) #在字符串中用字符起止偏移量生成子串并返回 sub(regex,replacement_str,string) #将正则表达式匹配到第一处内容替换成replacement_str gsub(regex,replacement_str,string) #类似上面,但是替换所有处 match(regex,string) #检查正则表达式是否能够匹配字符串,能则返回非0,否则返回0
对本文行字符迭代
while read line do echo $line done < file.txt #使用子shell方式 cat file.txt | (while read line; do echo $line; done) #迭代一行中每一个单词 for word in $line do echo $word done #迭代一个单词中的每一个字符 for((i=0;i<$(#word);i++)) do echo ${word:i:1} done
按列合并文件
paste file1 file2 file3 ... paste -d "," #列之间的定界符
打印不同行或样式之间的文本
awk 'NR==M, NR==N' filename seq 100 | awk 'NR==4, NR==6' #打印4--6行之间的文本 awk '/start_pattern/', /end_pattern/ filename
以逆序形式打印
tac file1 file2 ... seq 5 | tac seq 9 | awk '{info[NR]=$0; no=NR} END{for(;no>-1;no--){print info[no}}'
解析文本中的电子邮件
grep -E -o "[A-Za-z0-9]+@[A-Za-z0-9]+\.[a-zA-Z]{2,4}" email.txt
在文件中移除包含某个单词的句子
sed 's/[^.]*mobile phones[^.]*\.//g' sentence.txt #[^.] 可以匹配除.之外的任意字符,每个单词被//替换,注意//之间没有任何字符,也就是空字符
用awk模拟head,tail,tac
awk 'NR <= 10' filename #模拟head awk '{buffer[N%10]=$0} END{for(i=1;i<11;i++){print buffer[i%10]} }' filename #模拟tail awk '{buffer[NR]=$0} END{for(i=NR;i>0;i--){print buffer[i]} }' filename #模拟tac
文本切片与参数操作
var="THIS is a line of text" echo ${var/line/REPLACE} #结果 This is a REPLACE of text #通过制定字符串的起始位置和长度来生成子串 ${variable_name:start_pos:length} string=abcdefghijklmnopqrstuvwxyz echo ${string:4} #结果 efghijklmnopqrstuvwxyz #从第五个字符开始,打印8个字符 echo ${string:4:8} #结果 efghijkl #从后向前计数,最后一个字符索引记为-1,但必须放到括号内 echo ${string:(-1)} #结果 z echo ${string:(-2):2} #结果 yz
检测回文字符串
#类似abbc 这样的字符 #使用sed的反向引用,p用来打印匹配内容,下面这个命令可以匹配4个字符的回文 #如abbc, \(.\) 匹配第一个字符,\2是反向引用,\1引用第一个,于是匹配abbc这样的结构 sed '/^\(.\)\(.\)\2\1/p'
第五章 一团乱麻
网站下载
wget URL1 URL2 URL3 #下载后的文件名和原始一致进度输出到stdout wget ftp://example_domian.com/somefile.img wget -t 5 URL #指定重试次数 wget URL -o log wget --limit-rate 20k URL #对wget限速 wget -Q 100m URL #限制配额,最多只能下载100M wget --quote URL #同上 wget -C URL #断点续传 wget --mirror exampledomain.com #像爬虫一样递归的收集网页上的所有URL链接 wget -r -N -l DEPTH URL # -l 指定页面层级DEPTH,这个选项需要和-r(递归)一同使用 wget --user username --password pass URL #认证 #将网页以ASCII字符形式下载到文本文件中 lynx -dump URL > webpage_text.txt
curl入门
curl URL #默认将内容输出到stdout中 curl URL > index.html curl URL --slient #不显示进度信息 curl URL -o #将文结果写入文件,默认和URL中的文件名一致 curl URL -o index.html --progress #在下载过程中显示如 # 的进度条 curl URL/file -C offset #能够从特定的文件便宜出继续下载 curl --referer Referer_URL target_URL #如果referer是指定中的url,则跳转到那个URL中 curl URL --cookie "user-slynux;pass=hack" #指定cookie curl URL --cookie-jar cookie_file #将cookie存入另一个文件 curl --user-agent "Mozila/5.0" #指定user-agent头 curl -H "Accept-language: en" #指定请求头 curl URL --limit-rate 20K #限制curl下载速度 curl --max-filesize bytes #指定最大下载量 curl -u user:pass URL #进行认证 curl -I URL #只返回响应头 curl -head URL #同上 curl -v #显示详细内容
第六章 B计划
用tar归档
tar -c #创建文件 tar -f #指定文件名 tar -v #详细显示 tar -t #查看 tar -x #提取归档 tar -r #追加归档 tar -rvf original.tar new_file tar -Af file1.tar file2.tar #将file2.tar的内容合并到file1.tar中 tar -f archive.tar --delete file1 file2 ... #从归档中删除文件 tar -cf arch.tar.* --exclude "*.txt" #排除归档 tar --totals #打印归档后的总字节数 tar -u #只有比归档文件中的同名文件更新的时候才进行添加 #如 tar -uvf archive.tar filea 只有filea的文件内容修改时间更新的时候才对他添加 tar -d #打印出两者之间的差别 tar -j #指定bunzip2格式 tar -z #指定gzip格式 tar --lzma #指定lzma格式
用cpio归档
#用于将多个文件和文件夹存储为单个文件,同时还能保利麓所有的文件属性 touch file1 file2 file3 echo file1 file2 file3 | epio -ov > archive.cpio #归档 cpio -it < archive.cpio #列出归档 cpio -id < archive.cpio #从归档中提取文件
gzip压缩
gzip filename #会创建filename.gz的文件,并将原文件filename删除 gzip -l filename #列出压缩文件的属性信息 cat file | gzip -c > file #从stdin中读取并写入到stdout中 gzip --fast #最低压缩比 gzip --best #最高压缩比 gunzip filename.gz #解压缩 tar -zcvf archive.tar.gz [FILES] #创建gzip归档 tar -cvf archive.tar [FILES] #先创建归档 gzip archive.tar #再压缩 tar -ztvf archive.tar.gz #查看 tar -zxvf archive.tar.gz #提取 gzip -9 test.img # 1级最低,9级最高压缩率 zcat test.gz #直接查看压缩文件
bzip压缩
bzip2 filename #会创建filename.bz2文件,并删除原始的filename文件 cat file | gzip2 -c file.tar.bz2 #从stdin中读取并写入到stdout中 tar -jcvf archive.tar.bz2 [FILES] #创建归档 tar -cvf archive.tar [FILES] #先创建归档 bzip2 archive.tar #再压缩 tar -jtvf archive.tar.bz2 #查看 tar -jxvf archive.tar.bz2 #提取 bzip2 -9 test.img #和gzip一样从1--9级,1最快9压缩率最高
zip归档
zip archive_name.zip [SOURCE FILES/DIRS] #如 zip file.zip file #对目录和文件进行递归操作,和bzip2 gzip不同,zip不会删除原始文件 zip -r archive.zip folder1 file2 unzip file.zip #解压缩,不会删除原始文件 zip file.zip -u newfile #更新归档中的内容 zip -d arc.zip file.txt #从压缩归档中删除内容 zip -l archive.zip #列出归档文件中的内容
加密工具与散列
crypt <input_file> output_file Enter passphrass: #将stdin中接收一个文件以及口令,输出到output crpyt PASSPHRASE < input_file > encrypted_file #通过命令行参数来提供口令 crpyt PASSHRASE -d < encrypted_file > output_file #创建解密文件 gpg -c filename #加密文件 gpg filename.gpg #解密文件 base64 filename > outputfile #将文件编码为base64格式 cat file | base64 > outputfile base64 -d file > outputfile #解码base64文件 cat base64_file | base64 -d outputfile md5sum file #输出编码和文件名 sha1sun file #输出编码和文件名 openssl passwd -1 -salt SALT_STRING PASSWORD #利用openssl加盐散列加密
用rsync备份系统快照
rsync -av source_path destination_path #将源目录复制到目的端 rsync -a #比较进行归档 rsync -v #打印详细信息 rsync -av username@host:PATH destination #将远程机主机上的数据恢复到本地主机 rsync -z #传输时压缩数据 rsync --exclude "*.txt" #指定需要排除的文件 rsync --exclude-from FILEPATH #通过一个列表文件指定需要排除的文件 rsync -avz SOURCE DESTINATION --delete #备份时删除已不存在的文件
用dd克隆磁盘
dd if=SOURCE of=TARGET bs=BLOCK_SIZE count=COUNT dd if=/dev/sda1 of=sda1_partition.img #将一个分区复制到文件中 dd if=sda1_partition.img of=/dev/sda1 #用备份恢复分区 dd if=/dev/zero of=/dev/sda1 #永久性删除一个分区中所有数据 dd if=/dev/sda of=/dev/sdb #在容量相同的硬盘间进行克隆 dd if=/dev/cdrom of=cdrom.iso #制作CD ROM的镜像
其他
lzma 超高压缩率的squashfs文件系统
第七章 无网不利
联网知识
#打印可用的网络接口列表 ifconfig | cut -c-10 | tr -d ' ' | tr -s '\n' #打印eth1网卡的ip ifconfig eth1 | grep "inet" | cut -d ":" -f 2 | awk '{print $1}' #MAC地址欺骗 ifconfig eth1 hw enter [新的MAC地址] HWaddr 这个是MAC地址 inet addr IP地址 Bcast 广播地址 Mask 子网掩码 分配给当前系统的名字服务器可以通过/etc/resolv.conf查看 host www.baidu.com #列出这个域名的所有IP nslookup 域名 #类似host,会列出更多细节 route #显示路由表 route -n #指定以数字形式显示地址 traceroute 域名 #以显示分组途径的所有网关地址,用于测量源和目的经过了多少跳 ping -c 数量 域名 #发送多少ICMP包 #探测子网内所有活跃的机器,将循环体内放到 ( ) 内,可以并行执行脚本,也就是生成多个子shell,最后wait是等待 #上面的子shell执行技术 for ip in 192.168.0.1.{1..255} do ( ping $ip -c 2 &> /dev/null if [ $? -eq 0 ];then echo $ip is alive fi ) & wait done #fping可以ping一组ip fping -a #指定打印出所有活动主机的IP fping -u #打印出所有无法达到的主机 fping -g #指定从写作IP/mask的 "斜线--子网掩码" 记法或者起止IP地址记法中生成IP地址范围 fping -a 192.168.1/24 -g fping -d #对每一个echo回应进行DNS查询来返回主机名 fpipng -a -d 2> /dev/null < ip.list cat ip.list 192.168.0.86 192.168.0.9 192.168.0.6 #结果 www.local dnss.local
传输
scp SOURCE DESTIONATION scp user@remotehost:/home/path/filename source_filename #递归复制 scp -r /home/slynux user@remotehost:/home/backups scp -p #在复制文件的同时保留文件的权限和模式
SSH
ssh-keygen -t rsa 默认放到~/.ssh目录中 id_rsa.pub 是生成的公钥 id_rsa 是生成的私钥 公钥必须添加到远程服务器的 ~/.ssh/authorized_keys #添加一个密钥,会提示要输入密码,之后就不用输入密码了 ssh USER@REMOTE_HOST "cat >> ~/.ssh/authorized_keys" < ~/.ssh/id_rsa.pub ssh -C user@hostname COMMANDS #传输时压缩数据
网络监控
lsof -i #检测所有打开的端口 netatat -antp
第八章 当个好管家
统计磁盘使用情况
du FILENAME1 FILENAM2 ... du -a DIRECTORY #递归的统计目录下所有的文件大小 du -h #以KB,MB,GB的方式打印大小 du -c #统计所有文件和目录综合,最后会统计总大小 du -c *.txt du -b FILE(s) #打印字节 du -k FILE(s) #打印KB为单位的文件 du -m FILE(s) #打印MB为单位的文件 du -B BLOCK_SIZE FILE #打印以指定块为单位的文件大小 du - B 4 pcpu.sh du --exclude "*.txt" FILE(s) #排除指定的文件 du --exclude-from EXCLUDE.txt DIRECTORY #EXCLUDE.txt包含了需要排除的文件列表 du --max-depth 2 DIRECTORY #指定最大递归深度 du -s DIRECTORY #累计指定目录总大小 #找出指定目录中最大的10个文件 du -ak DIRECTORY | sort -nrk 1 | head find . -type f -exec du -k {} \; | sort -nrk 1 | head df #打印磁盘目录 df -h #按照MB,GB的格式打印
计算时间
time COMMAND real 从开始到结束的时间 user 进程再用户模式下花费的时间 sys 在内核模式下花费的时间
与当前登陆用户启动日志及启动故障的相关信息
who #获取当前登陆的相关信息 w #同who,但是更详细 users #当前登陆的用户列表 uptime #系统运行了多少时间以及平均负载 last #登陆会话信息,实际上是一个系统登陆日志,包括了tty,登陆时间状态灯信息 last -f /var/log/wtmp #明确指定日志文件 last USER #获取单个用户登陆会话信息 lastb #获取失败的用户登陆会话信息
打印历史记录中最常用的10条命令
printf "COMMAND\tCOUNT\n"; history | awk '{list[$4]++} END{ for(i in list){printf("%s\t%d\n",i,list[i])} }' | sort -nrk 2 | head
列出一小时内占用CPU最多的10个进程
LOOP=3600 for((i=0;i<LOOP;i++)) do ps -eo comm,pcpu | tail -n +2 >> /tmp/cpu_usage.$$ sleep 1 done cat /tmp/cpu_usage.$$ | awk '{process[$1]+=[$2]} END{ for(i in process){printf("%-20s % s",i,process[i);} }' | \ sort -nrk 2 | head
一些监控命令
watch #在某段时间间隔内不断监视某个命令的输出 watch ls #监控ls watch 'ls -l | grep xx' #监控ls和grep watch -d ls #高亮显示变化 inotifywait #用来收集有关文件访问的信息
用logrotate管理日志文件
配置目录位于/etcc/logrotate.d 可以为自己的日志文件编写一个特定的配置 cat /etc/logrotate.d/program /var/log/program.log { missingok notifempty size 30k compress weekly rotate 5 create 0600 root root } 其中/var/log/program.log 指定了日志文件路径,旧的日志文件归档之后也放入同一个目录中 配置参数 missingok 如果日志文件丢失则忽略,然后返回(不对日志文件行轮替) notifempty 仅当源日志文件非空时才对其进行轮替 size 30k 限制实施轮替的日志文件大小,可以用1M表示1MB compress 允许用gzip对较旧的日志进行压缩 weekly 指定进行轮替的时间间隔,可以是weekly,yearly,daily rotate 5 这是需要保留的旧日志文件的归档数据。在这里是5 所以这些文件名将会是program.log1.gz,program.log.2.gz直到program.log.5.gz create 0600 root root 指定所要创建的归档文件的模式,用户以及用户组
用syslog记录日志
/var/log是存储日志文件的公共目录,这里的文件是被称为syslog的协议处理的 由守护进程sylogd负责执行 linux中的一些重要日志文件 /var/log/boot.log 系统启动信息 /var/log/httpd apache web服务器日志 /var/log/message 发布内核启动信息 /var/log/auth.log 用户认证日志 /var/log/dmesg 系统启动洗洗 /var/log/mail.log 邮件服务器日志 /var/log/Xorg.0.log X服务器日志 logger LOG_MESSAGE logger this is a test log line tail -n 1 /var/log/message #查看刚刚输出的日志,如果是用logger命令,他默认记录到 #这个文件中 logger TAG this is a message #通过TAG将日志记录到不同的文件中
第九章 管理重任
收集进程信息
ps -f 显示更多的列 ps -e 系统的每一个进程 ps -ax 也类似ps -ef ps -o 指定输出的列,如ps -o comm ps -eo comm,pcpu | head -o 适用的参数如下 pcpu cpu占用率 pid 进程ID ppid 父进程ID pmem 内存使用率 comm 可执行文件名 cmd 简单明了(simple command) user 启动进程的用户 nice 优先级(niceness) time 累计的CPU时间 etime 进程启动后度过的时间 tty 所关联的TTY设备 euid 有效用户ID stat 进程状态 --sort对特定参数进行排序,+ 表示升序,- 表示降序 ps -eo comm,pcpu --sort -pcpu | head ps -C [command_name] #如 ps -C bash ps -C bash -o pid= #跟上pid= 就可以移除头部,只显示单个pid #类似pidof ps -u 有效用户 ps -U 真实用户 #如 ps -u root -U root -o user,pcpu ps -t TTY1, TTY2 ... #如 ps -t pst/0, pst/1 ps -eLf #NLWP是进程的线程数量,NLP是ps输出中每个条目的线程ID ps -eLF --sort -nlwp | head ps -e w # w表示宽松输出 ps -eo pid,cmd e | tail -n 3 # e表示显示进程依赖的环境变量
杀死进程以及发送或响应信号
kill -l #列出所有可用信号 kill PROCESS_ID_LIST #终止一个进程 kill -s SIGNAL PID #参数SIGNAL要么是信号名称,要么是信号数 具体如下: SIGHUP 1 对控制进程或终端进行挂起检测 SIGINT 2 当按下ctrl+c时发送该信号 SIGKILL 9 用于强行杀死进程 SIGTERM 15 默认用于终止进程 SIGTSTP 20 当按下ctrl+z时发送该信号 #强行杀死进程 kill -s SIGKILL PROCESS_ID kill -9 PROCESS_ID killall process_name killall -s SIGNAL process_name killall -9 process_name #强行杀死 killall -u USERNAME process_name #通过名称以及所属用户名指定进程 pkill process_name #pkill和kill类似,但是pkill接受的是进程名 #trap命令在脚本中用来为信号分配处理程序 trap 'echo `date`:can not terminate by ctrl+C' 2 #将对一个进程执行kill或者对某个进程执行ctrl+c 时候,会出现上面的提示 #说明已经捕捉了此信号
which,whereis,file,whatis与平均负载
#which命令用来找出某个命令的位置。我们在终端输入命令的时候无需知道对应的可执行文件位于 #何处。终端会在一组位置中查找这个命令,这一组位置由环境变量PATH指定 #如 which is #where和which命令类似,但是它不仅返回命令的路径,还能够打印出其对应的命令手册的位置以及命令源代码的路径 whereis ls #file 命令用来确定文件的类型 file /bin/ls #whatis命令会输出作为参数的命令的简短描述信息,这些信息是从命令手册中解析得来的 whatis ls #平均负载,显示了1分钟,5分钟,15分钟的平均负载情况,以及系统的开机时间 uptime
向用户终端发送消息
wall mesg
收集系统信息
hostname #打印当前系统的主机名 uname -n #打印当前系统的主机名 uname -a #打印linux内核版本,硬件架构等详细信息 uname -r #打印内核发行版本 uname -m #打印主机类型 cat /proc/cpuinfo #打印出CPU的相关信息 cat /proc/cpuinfo | head -n 5 | tail -1 #获得处理器名称 cat /proc/meminfo #打印内存的详细信息 cat /proc/partitions #打印分区的详细信息 fdisk -l #同上 lshw #同上
用/proc收集信息
系统中每一个运行的进程在/proc中都有一个对应的目录 environ 包含与进程相关联的环境变量 cwd 是一个到进程工作目录的符号链接 fd 包含了由进程所使用的文件描述符
用cron进行调度
cron表每一个条目都由6部分组成,按照下列顺序排列 分钟 0--59 小时 0--23 天 1--31 月份 1--12 工作日 0--6 命令 在指定时间执行的脚本或命令 * 表示指定命令在每一个时间段都执行 02 * * * * /home/slynux/test.sh #在每天的每个小时的第2分钟执行 00 5,6,7 * * /home/slynux/test.sh #要在每天的第5,6,7小时执行脚本 00 */12 * * 0 /home/slynux/script.sh #在周日的每个小时执行脚本 00 02 * * * /sbin/shutdown -h #在每天凌晨2点关闭计算机 crontab -e #手动编辑cron脚本 crontab -l #列出cron表中的内容 crontab -l -u slynux #指定用户名来查看其cron表 crontab -r 移除当前cron表中的内容
用户管理脚本
useradd [用户名] #增加用户 deluser [用户名] #删除用户 chsh USER -s SHELL #修改用户默认的shell usermode -L USER #锁定用户 usermode -U USER #解锁用户 chage -E DATE #处理用户账户的过期信息 其他选项 -m MIN_DAYS #将更改密码的最小天数修改成MIN_DAYS -M MAX_DAYS #设置密码有效的最大天数 -W WARN_DAYS #设置在前几天提醒需要更改密码 passwd USER #更改用户密码 addgroup GROUP #增加一个新用户组 delgroup GROUP #删除一个用户组 figer USER #显示用户信息
参考: