shell 学习笔记(17)

时间:2022-04-28
本文章向大家介绍shell 学习笔记(17),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

声明:转载需署名出处,严禁用于商业用途!

1601.关于rsync相同文件后 du 大小不一样的问题:
    不一样大小很正常,因为文件系统的block不一样,或者文件系统底层用了压缩什么的。
    因为du是块大小,ls是文件的实际大小,系统的块大小一般为4KB,
    所以du的文件一般比ls的结果要大,而且系统块大小可以更改。
1602.查看系统块大小:
    tune2fs -l /dev/sda1 | grep Block
1603.vi -u NONE -N 打开超大文件:
    关掉所有vim插件,用非兼容模式打开,否则语法分析等操作很占资源的
1604.shell整数运算支持自增运算:
    ((s+=++i)) 相当于 i=$(($i+1)) && s=$(($s+$i))
1605.ssh 会截获标准输入, 例如当while里套 ssh的时候,while 读了一个值之后,ssh会读取剩下的数据,
    可以 echo ""|ssh 或者 ssh -n 也可以避免
1606.find|xargs 文件名包含了单引号: xargs: unmatched single quote
    find -regex .... -printf %h\n
    find ...| grep ..| xargs -d 'n' -I {} dirname {}
    find ... -print0| grep ...| xargs -0I {} dirname {}
1607.用 dd 快速创建一个指定大小的空洞文件(4G压缩后只有4M):
    dd if=/dev/zero of=4G.txt bs=1G seek=4 count=0
1608.一个网段内,遍历哪些 ip 被占用可:
    nmap -v -sP 192.168.0.0/24|grep "up"|awk '{print $2}'
1609.如何清理操作及登录日志记录:
    > /var/log/lastlog
    > /var/log/wtmp
    > /var/log/auth.log
    > /var/log/messages
    > ~/.bash_history
    > ~/.viminfo        # grep cmd ~/*
    kill -9 $$
1610.echo 转义输出 16 进制ascii的字符形式:echo -e "x42"
1611.把一组 16 进制转换为ascii:
    n=54542D4632352D44362D5345
    echo $n | sed 's/(..)/\\x1/g' | xargs echo -e
1612.利用bash扩展列出所有目录:ls ${PATH//:/ }        #第一个//表示全局替换
1613.如何踢掉指定终端 tty/pts:
    pkill -t,根据tty杀也可以或者 pts,pkill -t pts/1  #-9 强制,-15 正常结束
1614.如何禁掉外网网卡:
    ifdown eth0
    cd /etc/sysconfig/network/
    vim ifcfg-eth0 
    #IP Config information for eth0:
    #IPADDR='113.108.1.9'
    NETMASK='255.255.255.128'
    STARTMODE='off'
    GATEWAY='113.1.1.1'
1615.把10000个文件切割成 100*100:
    find /root -name "*.*" -type f|split -l 100  -100a2     # -da2 用数字做后缀,限制两位,-a 默认就是两位,split -dl 100 也行
1616.man 重定向到文件出现退格符 ^H的解决办法:col -b 
1617.建立临时文件的方法:直接mktemp就行了,随机+判断文件是否存在,-u、--suffix、--tmpdir、XXX 或者直接 $$
1618.产生 a-z 的字母序列:
    echo {a..z} | awk 'NF=5'        #利用 bash 扩展
    awk 'BEGIN{for(i=97;i<101;i++)printf("%c ", i);printf("%cn", i)}'        #利用 ascii
1619.删除包含空格或tab的空行:
    grep -v -E "^[[:blank:]]*$"  或者  sed '/^s*$/d' 
1620.利用 split 返回数组长度判断字符串出现的位置:替换x~y之间,出现 abc 的字符串为 _XYZ_
    echo 1abc56abc01abc5678abc|awk -vn=6 '{print gensub("abc","_XYZ_",split(substr($0,1,n+10),a,"abc")-1,$0)}'    #有bug
    echo 1abc56abc01abc5678abc|awk '{n=6;start=substr($0,1,n-1);mid=substr($0,n,n+10);end=substr($0,n+11);gsub("abc","xyz",mid);print start""mid""end}'
1621.screen的妙用:在SSH断开的情况下,服务器端继续执行程序,甚至从公司回到家里,你都可以还原你的linux会话状态。
    screen -S test    #创建一个名为test的screen任务
                    #输入要执行的命令,enter
                    #Ctrl + a + d保存screen
    screen -ls        #查看所有screen
    
    screen -r test    #恢复screen

    exit            #退出screen
1622.crontab语法详解:    
    crontab [-u 用户名] [-elr]
    #crontab -e
    # 分  时  日  月  周    [用户]  command
    # 每分钟执行一次第一个参数可以写成样 1-59 或者 */1
    # .---------------- minute (0 - 59) 
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ... 
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)  OR sun,mon,tue,wed,thu,fri,sat 
    # |  |  |  |  |
    # *  *  *  *  *     command to be executed
1623.设置开机启动:
    vi /etc/rc.d/rc.local
1624.带有颜色的echo:
    设置颜色的格式: e[背景色;前景色;高亮me[0m
    e或33
    背景色:0 透明(使用终端颜色), 40 黑, 41 红, 42 绿, 43 黄, 44 蓝 45 紫, 46 青绿, 47白(灰)
    前景色:30 黑 31 红, 32 绿, 33 黄, 34 蓝, 35 紫, 36 青绿, 37 白(灰)
    高亮:高亮是1,不高亮是0。(m后面紧跟字符串)
1625.while read 读取多个文件需要定义多个FD:
    while read -u3 a && read -u4 b; 
    do
        echo $a=$b; 
    done 3<<<"$(seq 5)" 4<<<"$(seq 4 9)"
1626.awk 重组域替换行中的多个连续空格为一个:awk '$1=$1'
1627.linux关机:
    shutdown -y -i5 -g0
    sync;sync;init 5
    poweroff
1628.kill 默认信号是 -15 SIGTERM ,我们可以自定义进行捕获信号:
    while sleep 0.1
    do
        trap "echo 滚" 15    # bash a.sh & ; kill $!
    done
1629.获取命令名及时间:
    ps -eo time,cmd|awk -F: '/pad_/{print $2}'  
    ps ao time,cmd|awk -F: '/firefox/{print $1}'        #注意用了a 就不需要 - 了
1630.16进制加法:
    A='0x12345678' && A=$(awk 'BEGIN{printf("%x",'$A'+7)}') && echo $A
    A=12345678 && echo "obase=16;ibase=16;$A+7"|bc && echo $A
1631.让进程在后台可靠运行的几种方法: nohup/setsid/&/disown/screen
    disown是bash内部命令,nohup是外部命令
    disown跟bg,fg一样是针对job进行操作,nohup是针对命令操作
    disown -h 和nohup一样,在退出bash后,把进程的控制权都交给init
    我们可以根据不同的场景来选择不同的方案。nohup/setsid 无疑是临时需要时最方便的方法,
    disown 能帮助我们来事后补救当前已经在运行了的作业,而 screen 则是在大批量操作时不二的选择了。
1632.disown设置后台任务的方法:
    用disown -h jobspec 来使某个作业忽略HUP信号。
    用disown -ah 来使所有的作业都忽略HUP信号。
    用disown -rh 来使正在运行的作业忽略HUP信号。
    当使用过 disown 之后,会将把目标作业从作业列表中移除,
    我们将不能再使用jobs来查看它,但是依然能够用ps -ef查找到它。
    如果并没有把当前命令作为作业来运行,如何才能得到它的作业号呢?
    答案就是用 CTRL-z(按住Ctrl键的同时按住z键)了!
    CTRL-z 的用途就是将当前进程挂起(Suspend),然后我们就可以用jobs命令来查询它的作业号,
    再用bg jobspec 来将它放入后台并继续运行。需要注意的是,如果挂起会影响当前进程的运行结果,请慎用此方法。
1633.screen设置后台任务的方法:    
    如果有大量这种命令需要在稳定的后台里运行,如何避免对每条命令都做这样的操作呢?
    此时最方便的方法就是 screen 了。简单的说,screen 提供了 ANSI/VT100 的终端模拟器,
    使它能够在一个真实终端下运行多个全屏的伪终端。
    用screen -dmS session name 来建立一个处于断开模式下的会话(并指定其会话名)。
    用screen -list 来列出所有会话。
    用screen -r session name 来重新连接指定会话。
    用快捷键CTRL-a d 来暂时断开当前会话。
1634.zip、tar中文乱码问题:    
    zip格式里面不包含编码的,7zip和rar包含的
    所以gmail给附件打包的时候,如果文件名有中文,会提示你用什么编码。
    zip包里面乱码是zip的问题,zip的文件名乱码是zmoden没转换  
    tar也是这样的,里面不包含编码  
    rar里面带了编码,zip没带 ,要改zip的源码,这样就可以了,不过两边都要改。  
1635. 放在后台的程序,退出终端在登陆 jobs 就看不到了:
    jobs当然看不到了,jobs是针对当前shell进程的,你退出了,当然没了,不过进程还在。 
    父进程变成init了,这和 $! 获取最后一个后台进程 PID 一样的道理,都是针对当前 shell。
1636.read计算回车符:
    read也可以不用n,-n限制字符数,或者用-N,连n也算一个字符
1637.sed显示当前行号:sed -n '/hello/=' urfile
1638.获取 5 分钟以前的时间:
    date -d "-5min" "+%s"
1639.文件名中带有感叹号:可以禁用历史扩展:set +H
    echo mv "$i" ${i%%.*}.txt
1640.利用 od -c 的命令行模式观察输入内容的 ascii:
    od -c                 #回车
    输入你的内容        #回车
    ctrl+D                #输入结束,观察一下
1641.awk --non-decimal-data 做16进制或8进制加减:
    echo "0xFFFFFFFF,0x50004000,0x34"|awk -F, --non-decimal-data '{printf("0x%x, 0x%xn", $1, $2 + $3)}'
1642.tcpdump抓包没法看见IP:tcpdump -n -nn
    10:30:56.383831 IP xaim6.48621 > 172.23.9.123.mysql
1643.使用top监视所有匹配了foo字符的进程:
    top '-p' $(pgrep -d ' -p ' foo)
    top $(pgrep foo | sed 's|^|-p |g')
1644.给定字符,随机不重复:
    tr -dc 'abcde12345' </dev/urandom |head -c5
    awk -F '' 'BEGIN{srand();for(i=1;i<=5;i++)a[i]=int(rand()*100%10+1)}{for(i=1;i<=5;i++)printf $a[i];printf RS}' file
    echo abcde12345 | perl -ne 'print(((split("",$_))[sort({rand>.5} (0..9))])[0..5])'
    echo "a b c d e 1 2 3 4 5"| awk  '{srand();for(i=1;i<=6;i++) {k=int(rand()*10)%(11-i)+1; a[i]=$k; $k=""; $0=$0}; for(i in a) printf(a[i]) }'
1645.date中不用 @ 转换时间戳:
    date -d "UTC 1970-01-01 1234567890 secs"    #此方法在大于2038年的时候会有问题,即使是 64bit 也是有问题的。32473710849
1646.curl 获取外网ip:
    curl ifconfig.me/all        
    curl http://iframe.ip138.com/city.asp 2>/dev/null|sed -n 's#.*<center>|</center>.*##gp'
    主:如果用正则的反向引用需要注意终端编码。
1647.巧用通配符重命名单个数字文件:
    for i in ?.ogg; do mv $i 0$i; done
1648.seq和printf输出指定宽度的数字:
    seq -f '%02.g' 5
    printf '%02dn' {1..5}
1649.设置linux终端窗口的标题文字:
    PROMPT_COMMAND="echo -ne '33]0;$title07'"
1650.inode用完导致的磁盘空间不够:
    dumpe2fs -h /dev/hda6 | grep node            #查看inode总数及inode大小,inode是在分区的时候建立的
    tune2fs -l /dev/DEVICE | grep -i inode        #查看inode总数及inode大小,要调整总数需要重新格式化
    df -i        #查看各分区的inode使用情况
1651.awk判断ip公有还是私有:
    echo $IP | awk -F'.' '{
        if($1==10 || ($1==172&&$2>=16&&$2<=31) || ($1==192&&$2==168)) p=1;
        else p=0;
        print $0 "t" p;
    }'
    
    echo $1|awk -F"[^0-9]" 'NF==4&&$1<256&&$2<256&&$3<256&&$4<256{
        if($1==10||$1==192&&$2==168||$1==172&&$2>15&&$2<32)print
    }'
1652.awk mktime("1970 01 01 0 0 0") 由于时区问题导致不为 0 的问题:
    $ export TZ=UTC
    $ awk 'BEGIN{print mktime("1970 01 01 00 00 00")}'    # 0
    $ export TZ=UTC8
    $ awk 'BEGIN{print mktime("1970 01 01 00 00 00")}'    # 28800
    $ export TZ=UTC-8
    $ awk 'BEGIN{print mktime("1970 01 01 00 00 00")}'    # -28800
1653.安装libgcc_s.so.1出现错误Error: Protected multilib versions:
    可以模糊安装试试:yum install libgcc*
1654.为什么访问不同的网站,公网ip是不一样的:
    访问不同的地址,isp会选择不同的线路,他们每条线路出口都是nat转换的,所以看起来ip会是在任意地方的。
    小运营商都这么搞,叫“穿透接入” 
1655.sed从第n个字符开始全局替换:ng
    echo aaaaa|sed 's/a/b/2g'
1656.touch 不改变文件时间:
    touch -r oldfile newfile
1657.tar自动识别后缀:
    高版本的话,直接 tar axf,自动识别类型,不用管扩展名了
1658.当同时有标准输出和文件名的时候,很多命令都是以文件名为优先的: 例如cat或者sort:
    seq 3|cat a
1659.巧用sort+uniq进行按列去重:
    echo "c 150"|sort|uniq -u -w 1        #按第一列去重
1660.export 格式化列出所有环境变量:export -p
1661.获取 ls -lrt 的最后一列:
    ls -1 会将 ls -l 的长格式的最后一列打印出来,等价于 ls|xargs -0
1662.用 nc 与给定的主机端口进行一次 tcp 握手:
    nc -zvw 1 host port
1663.以另一用户身份运行一个命令:
    runuser -l  userNameHere -c 'command'    # runuser -l nginx -c 'ulimit -SHa'
    su - root -c "command"        # su - oracle -c 'ulimit -aHS'
1664.从匹配的下一行开始打印,直至结束:
    awk '/xyz/{tag=1;next}tag' file        # 第一次匹配至文件尾
    awk -vRS="[a-z]*xyz[a-z]*"  'END{print $0}' data        # 巧用 RS + END 打印最后一段匹配的
1665.xargs 处理带空格或特殊字符的文件:print0 | xargs -0
    -i {}对空白字符做了特殊处理,但是其它特殊字符还是不行的,试试touch "a'b" 
1666.shell ! 扩展通配符排除某个文件:
    shopt -s extglob然后cp 1/!(glo.txt) 2/这样也行
1667.在历史记录里查询某个命令打印它,而不是执行它:
    !<command>:p
1668.输出特定长度的随机数字:
    awk 'BEGIN{srand();a=rand()*100000000;printf("%08dn",a)}'
1669.语言字符环境设置:
    export LC_ALL=en_US.UTF-8
    export LANG=en_US.UTF-8
    export LC_CTYPE=en_US.UTF-8
1670.sed -e{} 固定行范围扩展:
    sed -e{,}{1,4}'s/S+ *//3'     #删除第1、4行的第3个域,注意前面的{,}
1671.中文与十六进制互换:
    echo -n "中"|xxd -ps
    反过来从0xd6d0得到汉字:echo -e "xd6xd0"         #0xd6d0 该结果与终端编码有关,类似 urlencode、urldecode
1672.awk --source进行外部函数调用:
    seq 10|awk -f func_awk -W source '{print;echo_hello()}'        #假设func_awk 是一个文件,里面定义了一个名为 echo_hello 的函数。
1673.tar 利用标准输出配合 gzip 创建压缩文件:
    tar cvf - "$folder" |gzip > /new_folder/$folder.tar.gz        # - 相当于文件占位符
1674.中文转16进制:
    echo -n 我 | iconv -t utf-16le | hexdump -e '"%d"'
1675.打印当前目录以及所有父目录的权限:
    namei -m $(pwd)
1676.单词边界与空串的区别:
    echo "abcdef"|sed 's/[^a-z]*/ /g'        #空串,注意此处 * 代表 0 次
    echo "abcde 1?2 *f"|sed 's/B/ /g'        #单词边界
1677.理解正则中的“单词边界与非单词边界”:
    aba 的单词边界为:baBbBab
    b 为单词边界        echo "fabcfde 1?2 *f"|grep --color 'bf'
    B 为非单词边界        echo "fabcfde 1?2 *f"|grep --color 'Bf'
1678.shell扩展通配 extglob 排除文件:
    shopt -s extglob; cp aaa/!(1*) bbb; shopt -u extglob
1679.tar中不能压缩 -z 和追加 -r 混用,-r 只能用在打包中:
    line 22: 18962 Aborted (core dumped) tar -zrvf $ip.tgz ${ip}_${ssn}.sql
    gunzip a.tgz -c|tar rf - b|gzip >b.tgz        #试过了,也不行,因为-r和-f -不兼容    
1680.双机信任中,拷贝公钥到远端机器:
    ssh-copy-id -i .ssh/id_rsa.pub user@server 
1681.sort -h 按人类易读的字节大小排序:
    find . -type f -print0 | xargs -0 du -h | sort -hr | head -10        #递归找出10个当前目录下最大的文件
1682.你可以  ls -l /proc/pid/fdinfo/  ,观察那个文件读到哪了 # cat /proc/XXXX/fdinfo/Y
1683.xargs 的行列合并:直接xargs为合并,xargs -n1 为拆分:
    echo a b d e b f a c e d | xargs -n1 | sort -u | xargs
1684.ping快速检测主机存活:
    ping -c1 -W 1 8.8.8.8        # -c次数 -W超时时间
1685.windows管理命令:msinfo32; systeminfo; control; gpedit.msc; msconfig; services.msc
1686.awk4.0 在asorti中对下标索引按数字排序: asorti(a,b,"@ind_num_asc") 
1687.rsync只有源和目的,没本地和远程,你可以本地到本地,也可以远程到远程。
    加了 -delete 之后,不是增量同步了(默认),而是镜像同步,会将 dest 上的多余文件删掉。
1688.cut -d 不支持多字符分隔符(如 t)的问题:
    echo -e "1t2"|cut  -dt -s -f2        #注意此处的 t 相当于t,-s的作用相当于sed -n,防止不匹配的时候全文输出
    cut默认就是制表符 t,就像 echo 不支持 t 要 -e 才行
    或者 t用 CTRL+V+TAB ;CTRL+V +I 代替
1689.获取管道里各个命令的执行状态:PIPESTATUS 数组
1690.Gnu Sed 定址匹配的几点说明:
    1. GNU 恰巧有许多对 POSIX sed 标准便利、省时的扩展。另外,GNU 没有 sed 早期专门版本的很多限制,如行长度限制 -- GNU 可以轻松处理任意长度的行.
    2. first~step   GNU扩展,选定 起始行~步长 的那些行。例如选择所有奇数行1~2;选择从第2行开始的,每隔3行 ‘2~3'
    3. /regexp/I 和 %regexp%I  : GNU扩展,忽略大小写.
    4. 0,/regexp/ : 这是唯一一个使用0作为行号不会报错的用法,一般情况下不存在”第0行”,在任何其他命令中使用0作地址都会报错.
    5. addr1,+N  匹配addr1和它后边的N行
    6. addr1,~N  匹配addr1和它后边的行,直到输入的下一行的行号是N的倍数
    例如:seq 10|sed -n '2,~3p'        #从2开始到第一个能被3整除的行为止
1691.<(cmds) 是bash进程替代(Process Substitution), 如果理解什么是命名管道,
    那么<(...)就是一个临时的命名管道,如果不理解, 
    可以简单的看作bash产生一个/dev/fdxxx的文件, 文件内容是cmds的标准输出
1692.关于 sh 软链接 bash 的问题:虽然 sh 链接了 bash,但单独执行他们仍可能不一样的结果:
    bash可以根据自己被 exec() 时的参数调整自己的行为, 你叫它sh它就按sh的规则玩, 你叫它bash它就按bash的规则玩,
    *nix系统里这样的例子太多了, 多个工具指向同一个文件, 按名字产生不同的结果
1693.找出所有可写的文件:find / -writable 2>/dev/null
1694.结束指定端口的进程:
    fuser -kn tcp 7072
    lsof -i:7072 |awk '{print $2}' |sort -u |xargs kill
1695.csplit:根据匹配的指定内容,按行分割文件,split可以按行数或者文件大小分割文件:
    csplit a /d/ {*}
    awk '/d66/{i++} {print > "file" i}' infile
1696.nc代替telnet扫描端口:
    nc -z -w 10 -u 192.168.1.106 137    # 成功会显示信息,不成功没有,可以返回值判断
    -z表示检测或者扫描端口  -w表示超时时间   -u表示使用UDP协议
1697.find -empty可以找出空目录,-size 0不行,-exec后面肯定要用;或者+来执行方式的
    find -print0|xargs -0,这两个参数就是互相配合的 
    如果你不理解+和;的区别,最好还是用xargs,而且xargs还能限制命令行长度,参数个数,比exec的+和;强大多了 
    ; 一个是每个参数执行一次,cmd arg1;cmd arg2;ls|xargs -I{} echo {} 或者 xargs -n1
    + 是所有参数执行一次,cmd arg1 agr2;ls|xargs echo
1698.(())算术扩展的类eval应用:
    a=1;b="";c=3
    for i in a b c; do (( $i==0?$i=0:$i )) ; done
    for i in a b c; do test -z ${!i} && eval $i=0; done
1699.tcpdump匹配http头:
    tcpdump -XvvennSs 0 -i eth0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854
    0x4745 为"GET"前两个字母"GE"
    0x4854 为"HTTP"前两个字母"HT"
1700.php-fpm 重载配置方法(解决新版不带reload/stop)
    php从5.3就可以集成php-fpm,但是集成后的php-fpm去掉了sbin/php-fpm (start|stop|reload)这些命令,只能启动。
    可以使用信号量,下pid为进程"php-fpm: master process"的pid
    重载进程和配置文件:kill -USR2 pid
              退出进程:kill -QUIT pid
              立即停止:kill -INT pid