x# 查看 os 详细信息,可用于Debian/Ubuntu/CentOS/redhatcat /etc/os-release# 查看 system 版本,只是一个link,可用于CentOS系cat /etc/system-release# 查看 CentOS/redhat 版本cat /etc/redhat-releasecat /etc/centos-release# 查看 suse 版本cat /etc/SuSE-release# 查看 openEuler 版本cat /etc/openEuler-release# 查看 alinux 版本cat /etc/alinux-release
xxxxxxxxxx# 系统欢迎信息cat /etc/issuecat /etc/motd# 显示系统的基本信息uname -acat /proc/version# 查看 Linux Standard Base (Linux标准库) 详细信息lsb_release -a
在CentOS7中,有三种定义的主机名:
“静态”主机名也称为内核主机名,是系统在启动时从/etc/hostname自动初始化的主机名。
“瞬态”主机名是在系统运行时临时分配的主机名,例如,通过DHCP或mDNS服务器分配。
“灵活”主机名也有人叫做“别名”主机名。
“灵活”主机名则允许使用自由形式(包括特殊/空白字符)的主机名,以展示给终端用户(如xh01@f5)。
“静态”主机名和“瞬态”主机名都遵从作为互联网域名同样的字符限制规则。
在CentOS 7中,有个叫hostnamectl的命令行工具,它允许你查看或修改与主机名相关的配置。
xxxxxxxxxx# 查看主机名hostnameuname -nhostnamectlcat /etc/hostnamesysctl kernel.hostname# 设置主机名hostname xxxhostnamectl set-hostname xxx
遵循 POSIX 规范,请参考:linux中的sh、dash、bash的区别
Bash 参考手册(Bash Reference Manual): https://www.gnu.org/software/bash/manual/
xxxxxxxxxx#!/bin/bash#日期:#作者:#邮箱:#作用:#版本:function usage {echo "Usage: myscript.sh [options]"echo "Options:"echo " -h, --help Show this help message and exit"echo " -f, --file FILE Path to input file"echo " -o, --output Path to output file"}# 处理命令行参数while [[ "$#" -gt 0 ]]; docase $1 in-h|--help) usage; exit 0;;-f|--file) FILE="$2"; shift;;-o|--output) OUTPUT="$2"; shift;;*) echo "Unknown parameter passed: $1"; usage; exit 1;;esac;shift;done
少用中文注释 以.sh为扩展名 成对{} [] () 空格[ ff ] if(fi) for while 语句一次性写完 缩进
启用严格模式,参考 set
xxxxxxxxxxset -xeuo pipefail-x : 在执行每一个命令之前把经过变量展开之后的命令打印出来。
-e : 遇到一个命令失败(返回码非零)时,立即退出。
-u :试图使用未定义的变量,就立即退出。
-o pipefail : 只要管道中的一个子命令失败,整个管道命令就失败。
pipefail 与-e 结合使用的话,就可以做到管道中的一个子命令失败,就退出脚本。
如果有时确实需要忽略个别命令的返回码,可以用 || true 。
xxxxxxxxxxsome_cmd || :some_cmd || true # 即使some_cmd失败了,仍然会继续运行
但有时候在已经设置了-u 后,某些地方还是希望能把未定义变量展开为空串,可以这样写:
xxxxxxxxxx${SOME_VAR:-}
# bash变量展开语法,可以参考:https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html防止重叠运行
xxxxxxxxxx# flock --wait 超时时间 -e 锁文件 -c "要执行的命令"# 例如:flock --wait 5 -e "lock_myscript" -c "bash myscript.sh"意外退出时杀掉所有子进程
原理就是利用 trap 命令在脚本退出时 kill 掉它整个进程组。 把下面的代码加在脚本开头区,实测管用:
xxxxxxxxxxtrap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXITtimeout 限制运行时间
xxxxxxxxxxtimeout 600s some_command arg1 arg2连续管道时,考虑使用 tee 将中间结果落盘,以便查问题
xxxxxxxxxxcmd1 | tee out1.dat | cmd2 | tee out2.dat | cmd3 > out3.datshellcheck一个静态的shell脚本分析工具,可以判断脚本哪里有异常,哪里可以优化,并且会给出对应的解决办法。
$UID:root用户值为0,非root用户值不为0
xxxxxxxxxxroot@ubuntu:~# echo $UID0fjcqy@ubuntu:/root$ echo $UID1000root@ubuntu:~# echo $SHELL/bin/bashroot@ubuntu:~# echo $HOME/rootroot@ubuntu:~# echo $USERrootroot@ubuntu:~# echo $PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
xxxxxxxxxx# 设置环境变量:export var=valuevar=value; export vardeclare -x var=value# 取消环境变量:unset var# 显示环境变量:env # 仅环境变量set # 包括环境变量、自定义变量、函数显示变量:echo $var定义变量:declare -x(全局) -a(数组) -i(整数) -p(只读) var注:+x,+p可以取消操作$$:Shell本身的PID(ProcessID)$!:Shell最后运行(即上一个)的后台Process的PID$?:最后运行的命令的结束代码(返回值),为0表示运行成功、2为权限不够$-:使用Set命令设定的Flag一览$*:所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。$@:所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。$#:添加到Shell的参数个数$0:Shell本身的文件名$1~$n:添加到Shell的各参数值。$1是第1参数、$2是第2参数… 、大于10:${10}。
作用:在当前bash环境下读取并执行FileName中的命令。该filename文件可以无"执行权限" 注:该命令通常用命令“.”来替代。 如:source bash_profile . bash_profile两者等效。 source(或点)命令通常用于重新执行刚修改的初始化文档。 source命令(从 C Shell 而来)是bash shell的内置命令。 点命令,就是个点符号,(从Bourne Shell而来)。就是顺序的执行文件里的命令而已。
作用:在当前相应的bash环境下新建一个子shell读取并执行FileName中的命令。该filename文件可以无"执行权限" 注:两者在执行文件时的不同,是分别用自己的shell来跑文件。 sh使用“-n”选项进行shell脚本的语法检查,使用“-x”选项实现shell脚本逐条语句的跟踪,可以巧妙地利用shell的内置变量增强“-x”选项的输出信息等。
作用:打开一个子shell来读取并执行FileName中命令。
该文件必须有可执行的权限。
注:运行一个shell脚本时会启动另一个命令解释器.
每个shell脚本有效地运行在父shell(parent shell)的一个子进程里. 这个父shell是指在一个控制终端或在一个xterm窗口中给你命令指示符的进程.shell脚本也可以启动他自已的子进程.这些子shell(即子进程)使脚本并行地,有效率地地同时运行脚本内的多个子任务.脚本里的变量设置在父进程中无效。脚本中的export仅仅作用于该脚本及其子脚本位置变量参数在向脚本传递参数时,可以使用此位置变量来获取参数。他们分别是:
source filename 与 sh filename 及./filename执行脚本的区别在那里呢? 1.当shell脚本具有可执行权限时,用sh filename与./filename执行脚本是没有区别得。./filename是因为当前目录没有在PATH中,所有"."是用来表示当前目录的。 2.sh filename 重新建立一个子shell,在子shell中执行脚本里面的语句,该子shell继承父shell的环境变量,但子shell新建的、改变的变量不会被带回父shell,除非使用export。 3.source filename:这个命令其实只是简单地读取脚本里面的语句依次在当前shell里面执行,没有建立新的子shell。那么脚本里面所有新建、改变变量的语句都会保存在当前shell里面。
举例说明:
1.新建一个test.sh脚本,内容为:A=1
2.然后使其可执行chmod +x test.sh
3.运行sh test.sh后,echo
Shell函数返回值,常用的两种方式:return,echo
shell函数的返回值,可以和其他语言的返回值一样,通过return语句返回。
接收方式:通过$? 获取返回值
示例:
xxxxxxxxxxfunction mytest() {echo "mytest function"echo "argv[1] = $1"if [ $1 = "1" ] ;thenreturn 1elsereturn 0fi}echo "mytest 1"mytest 1echo $?echo "mytest 0"mytest 0echo $?
注意:return返回值只能是整形数值(0-255),一般是用来表示函数执行成功与否的,0表示成功,其他值表示失败。因而用函数返回值来返回函数执行结果是不合适的。如果要硬生生地return某个计算结果,比如一个字符串,往往会得到错误提示:“numeric argument required”。 如果一定要让函数返回一个或多个值,可以定义全局变量,函数将计算结果赋给全局变量,然后脚本中其他地方通过访问全局变量,就可以获得那个函数“返回”的一个或多个执行结果了。
这种就类似于C语言中的全局变量(或环境变量)。
示例:
xxxxxxxxxx#!/bin/bash -g_var=function mytest2(){echo "mytest2"echo "args $1"g_var=$1return 0}mytest2 1echo "return $?"echoecho "g_var=$g_var"
结果:
xxxxxxxxxxmytest2args 1return 0g_var=1
函数mytest2通过修改全局变量(g_var)的值,来返回结果。
以上介绍的这两种方法在一般情况下都是好使的,但也有例外。
示例:
xxxxxxxxxx#!/bin/bash -function mytest3(){grep "123" test.txt | awk -F: '{print $2}' | while read line ;doecho "$line"if [ $line = "yxb" ]; thenreturn 0 # return to pipe onlyfidoneecho "mytest3 here "return 1 # return to main process}g_var=function mytest4(){grep "123" test.txt | awk -F: '{print $2}' | while read line ;doecho "$line"if [ $line = "yxb" ]; theng_var=0echo "g_var=0"return 0 # return to pipe onlyfidoneecho "mytest4 here "return 1}mytest3echo $?echomytest4echo $?echoecho "g_var=$g_var"
其中,test.txt中的内容如下:
456:kkk 123:yxb 123:test
输出如下:
yxb@yxb-laptop:~/文档/个人文档/shell函数返回值$ ./no_function.sh yxb mytest3 here 1 yxb g_var=0 mytest4 here g_var=
可以看到mytest3在return了以后其实没有直接返回,而是执行了循环体后的语句,同时看到mytest4中也是一样,同时,在mytest4中,对全局变量的修改也无济于事,全局变量的值根本就没有改变。这个是什么原因那? 笔者认为,之所以return语句没有直接返回,是因为return语句是在管道中执行的,管道其实是另一个子进程,而return只是从子进程中返回而已,只是while语句结束了,而函数体之后的语句会继续执行。 同理,全局变量在子进程中进行了修改,但是子进程的修改没有办法反应到父进程中,全局变量只是作为一个环境变量传入子进程,子进程修改自己的环境变量,不会影响到父进程。 因此在写shell函数的时候,用到管道(cmd &后台进程也一样)的时候一定要清楚此刻是从什么地方返回。
其实在shell中,函数的返回值有一个非常安全的返回方式,即通过输出到标准输出返回。因为子进程会继承父进程的标准输出,因此,子进程的输出也就直接反应到父进程。因此不存在上面提到的由于管道导致返回值失效的情况。
接收方式:可以通过$( )获取返回值。
示例4:
xxxxxxxxxx#!/bin/shfunction test(){echo "arg1 = $1"if [ $1 = "1" ] ;thenecho "1"elseecho "0"fi}echoecho "test 1"test 1echoecho "test 0"test 0echoecho "test 2"test 2
结果:
xxxxxxxxxxtest 1arg1 = 11test 0arg1 = 00test 2arg1 = 20
怎么?有没有搞错,这两个函数几乎没什么区别,对,它几乎就是return和echo不一样,但是有一点一定要注意,不能向标准输出一些不是结果的东西(也就是说,不能随便echo一些不需要的信息),比如调试信息,这些信息可以重定向到标准错误( > /dev/stderr )/文件中解决,特别要注意的是,脚本中用到其它类似grep这样的命令的时候,一定要记得 1>/dev/null 2>&1 来空这些输出信息输出到空设备,避免这些命令的输出。
xxxxxxxxxx#! /bin/shfunction test(){echo "test here"return 100}DD=`test`#echo excute overecho "return: $?"echo "DD: $DD"
如上shell代码段,执行结果是
xxxxxxxxxxreturn: 100DD: test here
如果 把#echo excute over注释去掉,执行结果是
xxxxxxxxxxexcute overreturn: 0DD: test here
也就是说:
DD是作为一个变量接收函数的标准输出,比如echo产生出来的信息,不包括报错之类的信息,如上如果函数test中调用test1,那么test和test1中的标准输出都会赋值给变量DD.
注意:DD=test , 符号不是单引号‘’,而是ESC下面的那个符号,该句话的意思是执行函数test结果赋值给DD,如果是单引号的话这句话是把字符串“test”赋值给变量DD,注意,这句话的执行结果不是赋值是否成功,而是函数的执行状态
总结:所以,可以总结一下函数返回值获取的方法:
1)用变量接收函数返回值,函数用echo等标准输出将要返回的东西打印出来。
2)用
终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关,shell,python,perl等均可以调用。 转义序列是以 ESC 开头,可以用 \033 完成相同的工作(ESC 的 ASCII 码用十进制表示就是 27, = 用八进制表示的 33)。
shell脚本中echo显示内容带颜色显示,echo显示带颜色,需要使用参数-e,格式如下:
xxxxxxxxxxecho -e "\033[字背景颜色;文字颜色m字符串\033[0m"# 例如:echo -e "\033[41;36m something here \033[0m"
其中41的位置代表底色, 36的位置是代表字的颜色 注: 1、字背景颜色和文字颜色之间是英文的";" 2、文字颜色后面有个m 3、字符串前后可以没有空格,如果有的话,输出也是同样有空格 下面是相应的字和背景颜色,可以自己来尝试找出不同颜色搭配 例
xxxxxxxxxxecho -e "\033[31m 红色字 \033[0m"echo -e "\033[34m 黄色字 \033[0m"echo -e "\033[41;33m 红底黄字 \033[0m"echo -e "\033[41;37m 红底白字 \033[0m"
xxxxxxxxxx字颜色:30—–37echo -e "\033[30m 黑色字 \033[0m"echo -e "\033[31m 红色字 \033[0m"echo -e "\033[32m 绿色字 \033[0m"echo -e "\033[33m 黄色字 \033[0m"echo -e "\033[34m 蓝色字 \033[0m"echo -e "\033[35m 紫色字 \033[0m"echo -e "\033[36m 天蓝字 \033[0m"echo -e "\033[37m 白色字 \033[0m"字背景颜色范围:40—–47echo -e "\033[40;37m 黑底白字 \033[0m"echo -e "\033[41;37m 红底白字 \033[0m"echo -e "\033[42;37m 绿底白字 \033[0m"echo -e "\033[43;37m 黄底白字 \033[0m"echo -e "\033[44;37m 蓝底白字 \033[0m"echo -e "\033[45;37m 紫底白字 \033[0m"echo -e "\033[46;37m 天蓝底白字 \033[0m"echo -e "\033[47;30m 白底黑字 \033[0m"最后面控制选项说明echo -e "\033[0m 关闭所有属性 \033[0m"echo -e "\033[1m 设置高亮度 \033[0m"echo -e "\033[4m 下划线 \033[0m"echo -e "\033[5m 闪烁 \033[0m"echo -e "\033[7m 反显 \033[0m"echo -e "\033[8m 消隐 \033[0m"echo -e "\033[30m 黑色字 \033[31m 红色字 \033[32m 绿色字 \033[33m 黄色字 \033[34m 蓝色字 \033[35m 紫色字 \033[36m 天蓝字 \033[37m 白色字 \033[0m"echo -e "\033[40m 黑色底 \033[41m 红色底 \033[42m 绿色底 \033[43m 黄色底 \033[44m 蓝色底 \033[45m 紫色底 \033[46m 天蓝底 \033[47m 白色底 \033[0m"echo -e "\033[nA 光标上移n行 \033[0m"echo -e "\033[nB 光标下移n行 \033[0m"echo -e "\033[nC 光标右移n行 \033[0m"echo -e "\033[nD 光标左移n行 \033[0m"echo -e "\033[y;xH设置光标位置 \033[0m"echo -e "\033[2J 清屏 \033[0m"echo -e "\033[K 清除从光标到行尾的内容 \033[0m"echo -e "\033[s 保存光标位置 \033[0m"echo -e "\033[u 恢复光标位置 \033[0m"echo -e "\033[?25l 隐藏光标 \033[0m"echo -e "\033[?25h 显示光标 \033[0m"
xxxxxxxxxxfor i in `seq 16 255`; do printf "\e[38;5;%sm %s\t" $i $i;done;echo ""
另外,如果希望运行的程序永远不退出,可以使用nohup命令,具体方法是: nohup命令参考 nohup 命令 用途:不挂断地运行命令。 语法:nohup Command [ Arg ... ] [ & ] 描述:nohup 命令运行由 Command 参数和任何相关的 Arg 参数指定的命令,忽略所有挂断(SIGHUP)信号。在注销后使用 nohup 命令运行后台中的程序。要运行后台中的 nohup 命令,添加 & ( 表示"and"的符号)到命令的尾部。 无论是否将 nohup 命令的输出重定向到终端,输出都将附加到当前目录的 nohup.out 文件中。如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。如果没有文件能创建或打开以用于追加,那么 Command 参数指定的命令不可调用。如果标准错误是一个终端,那么把指定的命令写给标准错误的所有输出作为标准输出重定向到相同的文件描述符。 退出状态:该命令返回下列出口值: 126 可以查找但不能调用 Command 参数指定的命令。 127 nohup 命令发生错误或不能查找由 Command 参数指定的命令。 否则,nohup 命令的退出状态是 Command 参数指定命令的退出状态。
Linux 将一个正在前台运行的任务放入后台。缺点就是无法获取程序输出了。
xxxxxxxxxx[jupyter@VM-16-12-centos ~]$ sleep 300 # 假设某程序正在运行。。。。^Z # 按下Ctrl-z[1]+ Stopped sleep 300[jupyter@VM-16-12-centos ~]$[jupyter@VM-16-12-centos ~]$ jobs[1]+ Stopped sleep 300[jupyter@VM-16-12-centos ~]$[jupyter@VM-16-12-centos ~]$ bg # 让暂时停掉的进程在后台运行起来[1]+ sleep 300 &[jupyter@VM-16-12-centos ~]$[jupyter@VM-16-12-centos ~]$ jobs[1]+ Running sleep 300 &[jupyter@VM-16-12-centos ~]$[jupyter@VM-16-12-centos ~]$ disown # 将作业(job)从 shell 的作业表中移除[jupyter@VM-16-12-centos ~]$[jupyter@VM-16-12-centos ~]$ jobs # 已经不在当前 shell 的作业列表中了[jupyter@VM-16-12-centos ~]$[jupyter@VM-16-12-centos ~]$ ps -ef |grep sleep # 进程还是后台运行着jupyter 10281 10199 0 16:25 pts/2 00:00:00 sleep 300jupyter 10582 10199 0 16:26 pts/2 00:00:00 grep --color=auto sleeproot 14574 760 0 Apr16 ? 00:11:54 /bin/sh -c sleep 100[jupyter@VM-16-12-centos ~]$[jupyter@VM-16-12-centos ~]$
在bash中,使用后台任务来实现任务的“多进程化”。在不加控制的模式下,不管有多少任务,全部都后台执行。也就是说,在这种情况下,有多少任务就有多少“进程”在同时执行。我们就先实现第一种情况:
实例一:正常情况脚本
xxxxxxxxxx#!/bin/bashfor ((i=0;i<5;i++));do{sleep 3;echo 1>>aa && echo "done!"}donecat aa|wc -lrm aa
这种情况下,程序顺序执行,每个循环3s,共需15s左右。
xxxxxxxxxx$ time bash test.shdone!done!done!done!done!5real 0m15.030suser 0m0.002ssys 0m0.003s
实例二:“多进程”实现
xxxxxxxxxx#!/bin/bashfor ((i=0;i<5;i++));do{sleep 3;echo 1>>aa && echo "done!"} & //&donewait //waitcat aa|wc -lrm aa
这个实例实际上就在上面基础上多加了一个后台执行&符号,此时应该是5个循环任务并发执行,最后需要3s左右时间。
xxxxxxxxxx$ time bash test.shdone!done!done!done!done!5real 0m3.011suser 0m0.002ssys 0m0.004s
效果非常明显。 这里需要说明一下wait的作用。wait是等待前面的后台任务全部完成才往下执行,否则程序本身是不会等待的,这样对后面依赖前面任务结果的命令来说就可能出错。例如上面wc -l的命令就报错:不存在aa这个文件。
以上所讲的实例都是进程数目不可控制的情况,下面描述如何准确控制并发的进程数目。
x#!/bin/bash# 2006-7-12, by wwy#———————————————————————————–# 此例子说明了一种用wait、read命令模拟多线程的一种技巧# 此技巧往往用于多主机检查,比如ssh登录、ping等等这种单进程比较慢而不耗费cpu的情况# 还说明了多线程的控制#———————————————————————————–function a_sub { # 此处定义一个函数,作为一个线程(子进程)sleep 3 # 线程的作用是sleep 3s}tmp_fifofile="/tmp/$.fifo"mkfifo $tmp_fifofile # 新建一个fifo类型的文件exec 6<>$tmp_fifofile # 将fd6指向fifo类型rm $tmp_fifofilethread=15 # 此处定义线程数for ((i=0;i<$thread;i++));doechodone >&6 # 事实上就是在fd6中放置了$thread个回车符for ((i=0;i<50;i++));do # 50次循环,可以理解为50个主机,或其他read -u6# 一个read -u6命令执行一次,就从fd6中减去一个回车符,然后向下执行,# fd6中没有回车符的时候,就停在这了,从而实现了线程数量控制{ # 此处子进程开始执行,被放到后台a_sub && { # 此处可以用来判断子进程的逻辑echo "a_sub is finished"} || {echo "sub error"}echo >&6 # 当进程结束以后,再向fd6中加上一个回车符,即补上了read -u6减去的那个} &donewait # 等待所有的后台子进程结束exec 6>&- # 关闭df6exit 0
sleep 3s,线程数为15,一共循环50次,所以,此脚本一共的执行时间大约为12秒 即: 15×3=45, 所以 3 x 3s = 9s (50-45=5)<15, 所以 1 x 3s = 3s 所以 9s + 3s = 12s
xxxxxxxxxx$ time ./multithread.sh >/dev/nullreal 0m12.025suser 0m0.020ssys 0m0.064s
而当不使用多线程技巧的时候,执行时间为:50 x 3s = 150s。
此程序中的命令 mkfifo tmpfile和linux中的命令 mknod tmpfile p效果相同。
区别是mkfifo为POSIX标准,因此推荐使用它。该命令创建了一个先入先出的管道文件,并为其分配文件标志符6。管道文件是进程之间通信的一种方式,注意这一句很重要
exec 6<>
注:下面的两个例子,和上面的例子一样的,只是注释不太一样,方便理解
例子1:
xxxxxxxxxx#!/bin/bashtemp_fifo_file=$$.info #以当前进程号,为临时管道取名mkfifo $temp_fifo_file #创建临时管道exec 6<>$temp_fifo_file #创建标识为6,可以对管道进行读写rm $temp_fifo_file #清空管道内容function f_sleep{sleep 2}temp_thread=2 #进程数for ((i=0;i<temp_thread;i++)) #为进程创建相应的占位doecho #每个echo输出一个回车,为每个进程创建一个占位done >&6 #将占位信息写入标识为6的管道for ((i=0;i<6;i++))doread #获取标识为6的占位{f_sleepecho $$,$i,`date`sleep 5echo $$,$i,`date`echo >&6 #>>>>>当任务执行完后,会释放管道占位,所以补充一个占位}& #>>>>>在后台执行{}中的任务done <&6 #将标识为6的管道作为标准输入wait #等待所有任务完成exec 6>&- #关闭标识为6的管道
例子2:
xxxxxxxxxx#!/bin/bashSEND_THREAD_NUM=13 #设置线程数,在这里所谓的线程,其实就是几乎同时放入后台(使用&)执行的进程。tmp_fifofile="/tmp/$$.fifo" # 脚本运行的当前进程ID号作为文件名mkfifo "$tmp_fifofile" # 新建一个随机fifo管道文件exec 6<>"$tmp_fifofile" # 定义文件描述符6指向这个fifo管道文件rm "$tmp_fifofile"for ((i=0;i<$SEND_THREAD_NUM;i++));doecho # for循环 往 fifo管道文件中写入13个空行done >&6for i in `seq 100`;do # 100 次 for 循环 开始read -u6 # 从文件描述符6中读取行(实际指向fifo管道){echo $i # 打印 isleep 3 # 暂停3秒echo >&6 # 再次往fifo管道文件中写入一个空行。} &# {} 这部分语句被放入后台作为一个子进程执行,所以不必每次等待3秒后执行#下一个,这部分的echo $i几乎是同时完成的,当fifo中13个空行读完后 for循环# 继续等待 read 中读取fifo数据,当后台的13个子进程等待3秒后,按次序# 排队往fifo输入空行,这样fifo中又有了数据,for语句继续执行pid=$! #打印最后一个进入后台的子进程idecho $piddonewait #等到后台的进程都执行完毕。exec 6>&- #删除文件描述符6exit 0
xxxxxxxxxx# 网卡数量eth_count=$(ls /sys/class/net/ | grep -E '^ens|^enp|^eth' | wc -l)echo "${eth_count}"[ "${eth_count}" -ne 1 ] && { echo "网卡数量不为1"; exit 1; }# 网卡名eth_name=$(ls /sys/class/net/ | grep -E '^ens|^enp|^eth')echo "${eth_name}"# ip地址ip_address=$(ip address | grep -A 5 "${eth_name}": | sed -n 's#.*inet \(.*\)/.*#\1#p')echo "${ip_address}"
xxxxxxxxxxroot@ubuntu:~# echo hello > test.logroot@ubuntu:~# cat test.loghelloroot@ubuntu:~# > test.logroot@ubuntu:~# cat test.logroot@ubuntu:~#-----------------------------------------root@ubuntu:~# echo hello > test.logroot@ubuntu:~# cat test.loghelloroot@ubuntu:~# echo >test.logroot@ubuntu:~# cat test.log(注: 有一空行)root@ubuntu:~#------------------------------------------root@ubuntu:~# echo hello > test.logroot@ubuntu:~# cat test.loghelloroot@ubuntu:~# cat /dev/null > test.logroot@ubuntu:~# cat test.logroot@ubuntu:~#
首先需要中文字体以便支持命令行终端的中文显示需求:
xxxxxxxxxxyum groupinstall "fonts"
碰到提示输入 y 回车继续安装,大概需要安装50MB的东西!
xxxxxxxxxx# CentOS 6vi /etc/sysconfig/i18n# CentOS 7vi /etc/locale.conf# 把内容改为LANG="zh_CN.UTF-8"
重启
xxxxxxxxxx[root@RHEL classes]# echo "hello!"-bash: !": event not found
因为 !" 会被当作命令行历史替换的符号来处理。不过在shell脚本中没有这样的问题。
不幸的是,你无法使用转义符来转义!:
xxxxxxxxxx[root@RHEL classes]# echo "hello\!"hello\!
在"!"符号后面加入空格或tab可以解决这个问题,但还不够完美,因为输出的字符也是加了空格后的,现象如下: echo "hello! " hello! (这里有一个空格)
在shell里如果是特殊字符,需要使用''单引号,来做特别标识才可以被解析成字符。
xxxxxxxxxx[root@RHEL classes]# echo hello'!'hello![root@RHEL classes]# echo ""hello'!'""hello![root@RHEL classes]# echo "hello'!'"-bash: !: event not found
有时我们需要RPM包中的某个文件,如何解压RPM包呢?
RPM包括是使用cpio格式打包的,因此可以先转成cpio然后解压,如下所示:
xxxxxxxxxxrpm2cpio *.rpm | cpio -div
在linux下查看进程用 ps -ef | grep XXX
通过ps及top命令查看进程信息时,只能查到相对路径,查不到的进程的详细信息,如绝对路径等。这时,我们需要通过以下的方法来查看进程的详细信息:
Linux在启动一个进程时,系统会在/proc下创建一个以PID命名的文件夹,在该文件夹下会有我们的进程的信息,其中包括一个名为exe的文件即记录了绝对路径,通过ll或ls –l命令即可查看。
ll /proc/PID
cwd符号链接的是进程运行目录; exe符号连接就是执行程序的绝对路径; cmdline就是程序运行时输入的命令行命令; environ记录了进程运行时的环境变量; fd目录下是进程打开或使用的文件的符号连接
xxxxxxxxxx# 单进程process=javals -al /proc/$(ps -ef | grep -v "grep" | grep ${process} | awk -F " " '{print $2}')/exe# 多进程process=zabbix_agentdfor pid in $(ps -ef | grep -v "grep" | grep ${process} | awk -F " " '{print $2}')dols -al /proc/${pid}/exedone
用bash shell写程序时,经常会用到for循环,特别是从1到100这种需求,这里记录几种shell中从1到100的循环方法
类c语言
xxxxxxxxxxfor ((i=1; i<=100; i ++))doecho $idone
in使用
xxxxxxxxxxfor i in {1..100}doecho $idone
seq使用
xxxxxxxxxxseq - print a sequence of numbersfor i in `seq 1 100`doecho $idone
mount -o remount,rw /
逗号前面无空格(切记),而且一定要有/这个 表示重新挂载为读写模式。
这个时候再 vi /etc/fstab 发现已经可以修改了,修改完毕,重启,正常。
xxxxxxxxxx# 找到已删除但是未释放空间的文件、及相关进程lsof | grep deleted
解决方法: 可以重启该进程;如果不能重启,可以置空该文件:
xxxxxxxxxx# 通过PID查看文件句柄ll /proc/PID/fd | grep delete.tmp# 将指定进程下文件句柄的文件置空echo > /proc/PID/fd/文件句柄
以下给出一些shell中判断字符串包含的方法,来源程序员问答网站 stackoverflow 以及segmentfault。
xxxxxxxxxxstrA="long string"strB="string"result=$(echo $strA | grep "${strB}")if [[ "$result" != "" ]]thenecho "包含"elseecho "不包含"fi
先打印长字符串,然后在长字符串中 grep 查找要搜索的字符串,用变量result记录结果 如果结果不为空,说明strA包含strB。如果结果为空,说明不包含。 这个方法充分利用了grep 的特性,最为简洁。
xxxxxxxxxxstrA="helloworld"strB="low"if [[ $strA =~ $strB ]]thenecho "包含"elseecho "不包含"fi
利用字符串运算符 =~ 直接判断strA是否包含strB。(这不是比第一个方法还要简洁吗摔!)
xxxxxxxxxxA="helloworld"B="low"if [[ $A == *$B* ]]thenecho "包含"elseecho "不包含"fi
这个也很easy,用通配符*号代理strA中非strB的部分,如果结果相等说明包含,反之不包含。
xxxxxxxxxxthisString="1 2 3 4 5" # 源字符串searchString="1 2" # 搜索字符串case $thisString in*"$searchString"*) echo Enemy Spot ;;*) echo nope ;;esa
这个就比较复杂了,case in 我还没有接触到,不过既然有比较简单的方法何必如此
xxxxxxxxxxSTRING_A=$1STRING_B=$2if [[ ${STRING_A/${STRING_B}//} == $STRING_A ]]then## is not substring.echo Nreturn 0else## is substring.echo Yreturn 1fi
这个也挺复杂
如果到stackoverflow上看其实还有更多形式,不过基本都属于以上几类了。
方法1:while循环中执行效率最高,最常用的方法。
while read line
do
echo
while IFS="" read -r line || [ -n "
如果需要跳过第一行,先read一次
{
read
while IFS="" read -r line || [ -n "
方法2 : 管道法: cat
方法3 for 循环。
for line in cat filename
do
echo ${line}
done
注释:这种方式是通过for循环的方式来读取文件的内容相比大家很熟悉了,这里不多说。
在各个方法中,for语句效率最高,而在while循环中读写文件时,第一种方式执行效率最高。
for逐行读和while逐行读是有区别的,如: $ cat t.txt 1111 2222 3333 4444 555
xxxxxxxxxxcat /etc/hosts | awk 'NR>1'cat /etc/hosts | sed -n '2,$p'
最近在学习shell编程,可是在《Linux程序设计》指定的网站上下载了源码,使用的时候却一直出问题。提示:”bash: ./here1:/bin/sh^M:损坏的解释器: 没有该文件或目录“。之后用vi编辑器打开文件,发觉每一行的最后有浅蓝色的字符'^M'。才知道了问题所在 其实并没什么奇怪的,出现这种错误的原因是因为Linux和Windows文本文件的行结束标志不同。在Linux中,文本文件用"\n"表示回车换行,表示成十六进制就是 0A ;而Windows用"\r\n"表示回车换行,表示成十六进制就是0D 0A。 。所以在Linux中使用Windows的文本文件常常会出现错误。为了避免这种错误,Linux提供了两种文本格式相互转化的命令:dos2unix和unix2dos,dos2unix把"\r\n"转化成"\n",unix2dos把"\n"转化成"\r\n"。 命令dos2unix和unix2dos的使用非常简单,格式为:dos2unix filename
(1)UTC 整个地球分为二十四时区,每个时区都有自己的本地时间。在国际无线电通信场合,为了统一起见,使用一个统一的时间,称为通用协调时(UTC,Universal Time Coordinated)。
(2)GMT 格林威治标准时间 (Greenwich Mean Time)指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。(UTC与GMT时间基本相同,本文中不做区分)
(3)CST 中国标准时间 (China Standard Time)【GMT + 8 = UTC + 8 = CST】
(4)DST 夏令时(Daylight Saving Time) 指在夏天太阳升起的比较早时,将时钟拨快一小时,以提早日光的使用。(中国不使用)
RTC(Real-Time Clock)或CMOS时钟,一般在主板上靠电池供电,服务器断电后也会继续运行。仅保存日期时间数值,无法保存时区和夏令时设置。
一般在服务器启动时复制RTC时间,之后独立运行,保存了时间、时区和夏令时设置。
在CentOS 6版本,时间设置有date、hwclock命令,从CentOS 7开始,使用了一个新的命令timedatectl。 Centos7 修改系统时区timezone,解决快、慢8小时问题 如果服务器用非 UTC 的时间,时区转换很容易不一致,而且对于有 daylight saving 的时区,每年多一小时少一小时的那两天,系统就会出现各种诡异现象。 服务器使用UTC时间,如要显示用户所在时区的本地时间,在客户端转化即可。
1、使用 date -R
xxxxxxxxxx[root@localhost ~]# dateFri Jul 3 11:17:51 CST 2020 <--- CST 中国标准时间[root@localhost ~]# date -RFri, 03 Jul 2020 11:17:54 +0800 <--- +0800 东八区[root@localhost ~]#
2、使用 timedatectl
xxxxxxxxxx[root@localhost ~]# timedatectlLocal time: Fri 2020-07-03 11:16:10 CST <---本地时间Universal time: Fri 2020-07-03 03:16:10 UTCRTC time: Fri 2020-07-03 03:16:10Time zone: Asia/Shanghai (CST, +0800) <---本地时区NTP enabled: yesNTP synchronized: yesRTC in local TZ: yesDST active: n/aWarning: The system is configured to read the RTC time in the local time zone.This mode can not be fully supported. It will create various problemswith time zone changes and daylight saving time adjustments. The RTCtime is never updated, it relies on external facilities to maintain it.If at all possible, use RTC in UTC by calling'timedatectl set-local-rtc 0'.[root@localhost ~]#
1、tzselect 看起来很像一个时区选择的工具,但并非如此。事实上tzselect仅仅是一个查看时区表示方式的『向导』程序而已。通过依次询问大洲→国家→城市,最后告诉你如何TZ变量的写法,比如北京时间是:Asia/Shanghai
可以编辑 /etc/profile或.profile文件,达到设置时区的目的
xxxxxxxxxxTZ='Asia/Shanghai'export TZ
默认情况下情况下,TZ属性是空,这时候是靠/etc/localtime文件来确定的时区。 此文件通常又是一个到/usr/share/zoneinfo/下各种时区文件的软连接。
xxxxxxxxxx[root@localhost ~]# ll /etc/localtimelrwxrwxrwx. 1 root root 25 2020-07-02 18:27:17 /etc/localtime -> ../usr/share/zoneinfo/UTC[root@localhost ~]#
通过修改/etc/localtime指向的软连接,进而修改系统的时区。比如下面的方法,将localtime文件设置为了北京时间:
xxxxxxxxxxln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime[root@localhost ~]# ll /etc/localtimelrwxrwxrwx 1 root root 33 2020-07-03 10:59:21 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai[root@localhost ~]#
xxxxxxxxxxdate -s
展示硬件时间
xxxxxxxxxx[root@localhost ~]# clockFri 03 Jul 2020 03:46:00 AM CST -0.798406 seconds[root@localhost ~]# hwclockFri 03 Jul 2020 03:48:35 AM CST -0.907819 seconds
写入硬件时间
xxxxxxxxxxclock -w
1、问题 对于装有Windows和Linux系统的机器,进入Windows显示的时间和Linux不一致,Linux中的时间比Windows提前8个小时。
2、解决方法 修改/etc/default/rcS,设置不使用UTC时间,设置如下: UTC=no
3、解释 Windows与Mac/Linux 缺省看待系统硬件时间的方式是不一样的:
因此,若要解决上述Windows和Linux显示时间不一致的问题,只要设置Linux/Unix/Mac不要将硬件时间当做UTC时间,而是作为本地时间即可。
xxxxxxxxxxdate -u:9:579:57 date: 17:57VM_WinXP VM_Linux|____________|||Windows Server 20089:57
xxxxxxxxxx## ASCII字符 转 十进制printf "%d" "'a"# ASCII字符 转 十进制function ascii_to_Dec() # args: a ascii character{printf "%d" "'$1"}## 十进制 转 ASCII字符t=`printf "%x" 97`printf "\\x$t"# 连在一起的写法printf \\x`printf %x 97`# 十进制 转 ASCII字符function Dec_to_ascii() # args: a decimal number{printf \\x`printf %x $1`}## 计算下一个ASCII字符,如: B 到 C; # 到 $function next_letter() # args: a ascii character{printf "\\x$(printf %x $(printf "%d+1\n" "'$1" | bc))\n"}
xxxxxxxxxx[ $(ls -A /var/www/html/reg_for_sms | wc -w) = 0 ] && echo empty[ "$(ls -A /root/df)" = "" ] && echo empty
注意ls命令带了-A参数,这是为了将目录中隐藏文件列出,同时排除.和..,如果不加这个参数,判断结果是不准确的。
xxxxxxxxxx[root@CentOS ~]# ls -Aalias.txt .bashrc docker .tcshrcanaconda-ks.cfg .cache docker_reg_for_sms .viminfo.bash_history centos6.6.img docker_setup_rhel7.2.tar.gz.bash_logout .config docker_zt.bash_profile .cshrc
xxxxxxxxxx# 查看所有[root@RHEL ~]# sysctl -avi /etc/sysctl.conf# 内核保持的未被 ACK 的 SYN 包最大队列长度,超过这个数值后,多余的请求会被丢弃。默认128。# 每一个连接请求(SYN报文)都需要排队,直至本地服务器确认(ACK),该变量就是控制每个端口的 TCP SYN队列长度的。net.ipv4.tcp_max_syn_backlog = 204800# somaxconn 是一个 socket 上等待应用程序 accept() 的最大队列长度,默认值通常为128。# 在一个 socket 进行 listen(int sockfd, int backlog) 时需要指定 backlog 值作为参数,如果这个 backlog 值大于 somaxconn 的值,最大队列长度将以 somaxconn 为准,多余的连接请求将被放弃,此时客户端可能收到一个 ECONNREFUSED 或忽略此连接并重传。net.core.somaxconn = 102400net.netfilter.nf_conntrack_max = 655360net.nf_conntrack_max = 655360# 生效sysctl -p# 快速修改echo net.ipv4.tcp_max_syn_backlog = 204800 >> /etc/sysctl.confecho net.core.somaxconn = 102400 >> /etc/sysctl.confecho net.netfilter.nf_conntrack_max = 655360 >> /etc/sysctl.confecho net.nf_conntrack_max = 655360 >> /etc/sysctl.confsysctl -p
ulimitulimit 是为用户设定资源限制的工具。
xxxxxxxxxx# 查看所有[root@RHEL ~]# ulimit -acore file size (blocks, -c) 0data seg size (kbytes, -d) unlimitedscheduling priority (-e) 0file size (blocks, -f) unlimitedpending signals (-i) 14797max locked memory (kbytes, -l) 64max memory size (kbytes, -m) unlimitedopen files (-n) 1024pipe size (512 bytes, -p) 8POSIX message queues (bytes, -q) 819200real-time priority (-r) 0stack size (kbytes, -s) 10240cpu time (seconds, -t) unlimitedmax user processes (-u) 14797virtual memory (kbytes, -v) unlimitedfile locks (-x) unlimited# 查看最大文件描述符ulimit -n# 临时修改用户级别的最大打开文件数ulimit -n 65536# 永久修改整个系统最大打开文件数vi /etc/security/limits.conf 添加* soft nofile 65536* hard nofile 65536sed -i '/# End of file/i\* soft nofile 65536' /etc/security/limits.confsed -i '/# End of file/i\* hard nofile 65536' /etc/security/limits.conf
修改以后保存,注销当前用户,重新登录,参数即可生效。解释:
第一列表示用户和组(@开头)。第二列表示软限制还是硬限制,第三列表示限制的资源类型,第四列表示限制的最大值。
hard和soft的区别: soft是一个警告值,而hard则是一个真正意义的阀值,超过就会报错,一般情况下都是设为同一个值。 core是内核文件,nofile是文件描述符,noproc是进程,一般情况下只限制文件描述符数和进程数就够了
在使用systemd而不是sysvinit的系统上,/etc/security/limits.conf将不再对systemd管理的服务生效,但仍然对登录进程生效。 这会导致登陆后查看ulimit -a和/proc/{pid}/limits不一致。 另一个常见的问题是使用类似于supervisor的守护进程,而守护进程由systemd管理,导致误认为是supervisor的配置问题。这个问题可以通过查看supervisor自身的ulimit来判断cat /proc/{supervisor pid}/limits。
在配置里面加上配置
xxxxxxxxxxvi /usr/lib/systemd/system/xxx.service[Service]# (file size)LimitFSIZE=infinity# (cpu time)LimitCPU=infinity# (virtual memory size)LimitAS=infinity# (locked-in-memory size)LimitMEMLOCK=infinity# (open files)LimitNOFILE=64000# (processes/threads)LimitNPROC=64000
cpu信息
xxxxxxxxxx在top命令的显示界面,按数字键1cat /proc/cpuinfolscpu# cpu 温度echo $[$(cat /sys/class/thermal/thermal_zone0/temp)/1000]
内存信息
xxxxxxxxxxtopfreecat /proc/meminfo
硬盘信息
xxxxxxxxxx# 硬盘型号cat /sys/block/*/device/model
#格式化mkfs.ext4 /dev/sdb#挂载mount /dev/sdb /data#在 /etc/fstab 文件中添加条目以便永久启动时自动挂载cat >> /etc/fstab << EOF/dev/sdb /data ext4 defaults 0 0EOF``# 最好使用UUID挂载ls -l /dev/disk/by-uuid/# vi /etc/fstabUUID=597bcf03-a487-496e-bc33-c6de0fa12ee3 /data ext4 defaults 0 0
如果安装linux的时候没有分swap分区,那么你可以:
xxxxxxxxxx/dev/sda9 swap swap defaults 0 0
这里假定是sda9。
如果没有空间,那么
检查增加后的交换情况:
xxxxxxxxxx[root@RHEL ~]# free -mtotal used free shared buffers cachedMem: 1869 137 1732 0 8 52-/+ buffers/cache: 76 1792Swap: 256 0 256
最后注意:修改fstab的时候一定要在最后有空行,不然会提示warning的。
创建swap文件
如果你的硬盘空间已经全部分配给其他分区,也没有多余的预算新添购硬盘,我们可以利用swap文件的方式增加虚拟的swap空间,不过执行性能会较实际的swap分区差.
产生swap文件 要创建swap文件,执行dd命令,新增一个256MB的swap文件:
xxxxxxxxxx# dd if=/dev/zero of=/tmp/myswap bs=32k count=8192
(bs=32k指定每个扇区占用32kb,读入了8192+0个区段,输出了8192+0个区段) 注意:bs参数的目的在于指定每次读取及输入多少个bytes;由于磁盘存取的最小单位为扇区,因此设置bs也等于设置每个扇区的大小;而count的目的则在指定可以使用多少个扇区.因此,可以使用的硬盘空间就等于bscount.以上范例为例,可以使用的硬盘空间等于328192=262144 (KB),亦等于256MB.
执行上述命令后,会在/tmp目录中创建一个256MB的myswap文件
格式化及启动swap文件 接下来执行mkswap命令,将myswap文件格式化成s文件系统,系统才能使用,切换到/tmp目录,并执行以下命令:
xxxxxxxxxx# mkswap myswap (#将文件格式化为swap文件格式)setting up swapspace version 1 , size = 262144 KB# swapon /tmp/myswap (#启动swap分区)
要停止使用新创建的swap文件,只要执行 swapoff /tmp/myswap命令即可.
开机时自动启动新添加的swap分区 如果每次开机后都要执行swapon命令启动swap分区或者文件,这太麻烦了.这时可以利用文字编辑器在/etc/fstab文件加一行,好让开机时自动启动swap分区及文件:
xxxxxxxxxx/dec/hdb5 swap swap defaults 0 0 (开机时启动此swap分区)/tmp/myswap swap swap defaults 0 0 (开机时启动此swap文件)
find是最常使用和最强大的查找命令,可以找到任何想查找找的文件
用法如下: $ find <指定目录> <指定条件> <指定动作>
如果不加参数,默认搜索当前目录及其子目录,并且不过滤任何结果(也就是返回所有文件)
实例:
$ find /home -name 'a*' 搜索home目录(含子目录)中所有文件名以a开头的文件
$ find /home -name 'a*' -ls 搜索home目录(含子目录)中所有文件名以a开头的文件并显示它们的详细信息。
$ find /home -type f -mmin -10 搜索home目录中所有过去10分钟中更新过的普通文件,如果不加-type f参数,则搜索普通文件+特殊文件+目录。
locate命令实质上是"find -name"的另一种写法,但是要比后者快得多,原因在于它不搜索具体目录,而是搜索一个数据库(/var/lib/locatedb),这个数据库中含有本地所有文件信息。Linux系统自动创建这个数据库,并且每天自动更新一次,所以使用locate命令查不到最新变动过的文件。为了避免这种情况,可以在使用locate之前,先使用updatedb命令,手动更新数据库。
实例:
$ locate /etc/sh 搜索etc目录下所有以sh开头的文件
$ locate ~/m 搜索home录下,所有以m开头的文件。
$ locate -i ~/m 搜索用户主目录下,所有以m开头的文件,并且忽略大小写。
whereis命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b)、man说明文件(参数-m)和源代码文件(参数-s),如果省略参数则返回所有信息
实例: $ whereis grep
which命令是在PATH变量指定的路径中搜索某个系统命令的位置,并且返回第一个搜索结果。也就是说,使用which命令就可以看到某个系统命令是否存在以及执行的到底是哪一个位置的命令
实例: $ which grep
type命令其实不能算查找命令,它是用来查看某个命令是由shell自带的还是由shell外部的独立二进制文件提供的,如果一个命令是外部命令,使用-p参数会显示该命令的路径,相当于which命令
实例:
$ type cd 输出 "cd is a shell builtin"
$ type grep 输出 "grep is aliased to `grep --color=auto'"
$ type -p grep 加上-p参数后就相当于which命令。
Ctrl + b:同键盘左键,向左移动光标。 Ctrl + f:同键盘右键,向右移动光标。
Alt + b:向前移动一个词的距离。如果shell终端配置启用了可以通过快捷键打开菜单,会发生冲突,解决办法是禁用这个功能或者和Shift键一起使用。 Alt + f:向后移动一个词的距离。如果shell终端配置启用了可以通过快捷键打开菜单,会发生冲突,解决办法是禁用这个功能或者和Shift键一起使用。
ESC + b 移动到当前单词的开头,已在单词的开头则移动到上一个单词的开头 ESC + f 移动到当前单词的结尾,已在单词的结尾则移动到下一个单词的结尾
Ctrl + a:移动光标到命令行首。 Ctrl + e:移动光标到命令行尾。
Ctrl + x + x:光标在命令行中光标最后两次出现的位置间进行切换。
Ctrl + h:同Backspace,退格向左删除。 Ctrl + d:同delete,向右删除。
Ctrl + w:剪切光标之前的一个词。 Alt + d:剪切光标之后的一个词。
Ctrl + u:从当前光标所在位置向左剪切全部命令。 Ctrl + k:从当前光标所在位置向右剪切全部命令。
Alt + u:从当前字符开始的一个字符串,字母替换为大写。 Alt + l:从当前字符开始的一个字符串,字母替换为小写。
Alt + c:当前字符变为大写,向后的一个字符串全部变为小写。
Ctrl + t:交换光标前的最后两个字符。
Alt + t:交换当前单词和前一个单词的位置。如果shell终端配置启用了可以通过快捷键打开菜单,会发生冲突,解决办法是禁用这个功能或者和Shift键一起使用。
Esc + t:交换光标前的最后两个单词。
向上向下下箭头:查看历史命令,只要按上下箭头即可,命令一个一个显示。
Ctrl + p:显示上一条命令,同向上箭头。 Ctrl + n:显示下一条命令,同向下箭头。
ctrl + r 检索历史命令 linux或者类unix操作系统中 ctrl + r 按键代表reverse-i-search,它可以方便的检索历史命令,直接进行执行,下面简单介绍一下这一神奇的基本用法: Ctrl+R 出现提示后,输入关键词,即可找出历史执行命令,下面有两个选择: 输入回车:直接执行命令 输入右方向键:在终端打出整个命令,但是没有执行,用户可以编辑修改,或者输入回车执行。 再次输入Ctrl+R: 代表继续检索,程序将显示其他关键词的历史。
Tab:按一次补全,按两次列出所有相关信息。 Esc + .:插入最后一个参数,也就是上一个命令的最后一个参数或者叫字符串。 Ctrl + v:粘贴最近剪切的文本。 Ctrl + v + 特殊字符:添加一个特殊字符,如tab等。
yarn top\ clickhouse-client --format=Pretty 的输出结果都带有类似^[[1m、^[[0m的控制字符。使用sed命令移除,\x1B\[1m表示控制字符^[[1m的转义序列,^[就是16进制的1B。
xxxxxxxxxxsed -i 's/\x1B\[.m//g' ${result_file}