10种一些不太知名的bash功能你知道吗?

简介
我之前的一篇文章比我预想的更受欢迎,因此我想再写一篇文章来介绍一些不太知名的bash功能
正如之前所言,由于我觉得bash是一种要经常使用(且需理解)的技术,所以我在研究bash时写了一本书。虽然许多人并不熟悉bash,但我觉得他们也认为非常重要便足够令人欣喜。
1)^x^y^
我总在使用的一个小技巧。
从来没有输入过类似的命令?
$ grp somestring somefile-bash: grp: command not found
哎,这个命令敲错了,所以你要敲“↑”,然后敲”←“直到”p“,然后输入”e再执行。
或者这样输入:
$ ^rp^rep^grep 'somestring' somefile$
你可能需要注意的一个细节是:
$ grp rp somefile$ ^rp^rep^$ grep rp somefile
如果你想搜索“rep”,那你就要深入研究man page,学会使用这个更强大的命令:
$ grp rp somefile$ !!:gs/rp/repgrep rep somefile$
我不会在这里解释这个用法。。。
2)pushd/popd
这个在脚本中非常好用,特别是在循环中
如下所示,假设你正在写一个进入退出文件夹的for循环:
for d1 in $(ls -d */)do # store original working directory. original_wd=$(pwd) cd $d1 for d2 in $(ls -d */) do pushd $d2 # do something popd done # return to original working directory cd ${original_wd}done
你可以像这样使用pushd栈来重写上方代码:
for d1 in $(ls -d *)do pushd $d1 for d2 in $(ls -d */) do pushd $d2 # do something popd done popddone
它可以追踪记录你切换的目录并进行入栈或出栈
注意,当使用pushd出现错误时,可能会丢失栈的记录并且popd多次。因此你可能会想要在脚本中使用set -e(见上一篇文章)
当然也可以用cd -,但是它不会使用栈——仅仅返回前一个目录
cd ~cd /tmpcd blahcd - # back to /tmpcd - # back to 'blah'cd - # back to /tmpcd - # back to 'blah' ...
3) shopt vs set
这两个命令困扰了我一阵子。
两者之间有什么不同呢?
set在之前的文章已经介绍过了,而shopt看起来与之相似。只输入shopt会显示一系列选项:
$ shoptcdable_vars offcdspell oncheckhash offcheckwinsize oncmdhist oncompat31 offdotglob off
我在这里(here)找到了一些答案。
从根本上说,似乎有一系列的bash(和其他shells)建立在sh之上,而添加shopt命令则为设置额外的shell选项提供了一种方式
但是我也不确定……如果你知道为什么,请告诉我。
4)here docs 与 here strings
“here docs”是在shell中用一些语句创建的文件。
“诀窍”很简单。定义一个用于结束的单词,则在这个单词单独出现在一行之前的所有输入行将构成文件。
像这样:
$ cat > afile it has three lines> someendstring alone on a line will save the doc> someendstring$ cat afilehere is a docit has three linessomeendstring alone on a line will save the doc$
注意:
· 如果结束单词不是“单独”出现在一行中,那它可以构成文件
· someendstring通常是end,但这仅仅只是习惯
更鲜为人知的是“here string”:
$ cat > asd <<< 'this file has one line'
5)字符串变量的操作
以前你可能是像下面展示的那样写代码,用sed一类的工具来操作字符串:
$ var='headermy voice is my passwordfooter'$ pass=$(echo $var | sed 's/^header(.*)footer/1/')$ echo $pass
但是你可能不知道bash本身也是可以的。
这意味着你可以省去大量的sed和awk。
一种重写上述代码的方式如下所示:
$ var='headermy voice is my passwordfooter'$ pass=${var#header}$ pass=${pass%footer}$ echo $pass
·#表示“从字符串开头开始匹配并删除所给的模式串”
·%表示“从字符串结尾开始匹配并删除所给的模式串”
在我的电脑上,后一种方法比前一种快两倍。并且(令我吃惊的是),他的速度跟类似功能的python脚本速度大致相当
如果你想使用通配符(见前文)模式串并采用贪婪模式,你需要双写:
$ var='headermy voice is my passwordfooter'$ echo ${var##header*}$ echo ${var%%*footer}
6)变量的默认值
这些对写脚本来说非常好用。
如果你有一个没有赋值的变量,你可以像这样给它“赋默认值”
创建一个default.sh文件,写入如下内容:
#!/bin/bashfirst_arg=${1:-no_first_arg}second_arg=${2:-no_second_arg}third_arg=${3:-no_third_arg}echo ${first_arg}echo ${second_arg}echo ${third_arg}
现在执行chmod +x default.sh并用./default.sh first second来运行脚本:
观察第三个参数的默认值是如何被分配的,而不是前两个。
你也可以直接用${var:=defaultval}(等号,不是破折号),但是注意这不适用于脚本或函数中的位置变量。尝试修改上面的脚本来看它是如何失败的。
7)traps
当一个信号被送到脚本时,内建的trap可以用于“捕获”
下面是我用在自己的chepci脚本中的一个例子:
function cleanup() { rm -rf ${build_dir} rm -f ${lock_file} # get rid of /tmp detritus, leaving anything accessed 2 days ago+ find ${build_dir_base}/* -type d -atime +1 | rm -rf echo cleanup done } trap cleanup term int quit
任何使用term信号的ctrl-c,ctrl-或终止程序的操作将会首先调用cleanup
注意:
·trap的逻辑可能非常棘手(例如处理信号竞争条件)
·kill信号不能以这种方式捕获
但是大多数情况下,我会把它用于类似上述的‘cleanup’中,来达成函数的目的。
8)shell变量
了解可用的标准shell变量是非常值得的。这些是我最喜欢的。
random
不要依赖这个来加密堆栈,但你可以生成随机数字,例如在脚本中创建临时文件时:
$ echo ${random}16313$ # not enough digits?$ echo ${random}${random}113610703$ newfile=/tmp/newfile_${random}$ touch $newfile
reply
不在需要给read一个变量名称
$ readmy input$ echo ${reply}
lineno 与 seconds
方便调试
$ echo ${lineno}115$ echo ${seconds}; sleep 1; echo ${seconds}; echo $lineno174380174381116
注意,即便使用;来隔开命令,上面的代码也要分两行
tmout
可以用来超时读取,在一些脚本中真的很好用
#!/bin/bashtmout=5echo you have 5 seconds to respond...readecho ${reply:-noreply}
9) extglobs
如果你真的沉迷bash不能自拔,那么你可能想要增强你的通配功能。你可以通过设置shell中的extglob选项。这是设置方法:
shopt -s extgloba=12345678901234567890b= ${a}
现在来看看你是否能指出以下这些语句各自的功能:
echo b |${b}|echo b#+( ) |${b#+( )}|echo b#?( ) |${b#?( )}|echo b#*( ) |${b#*( )}|echo b##+( )|${b##+( )}|echo b##*( )|${b##*( )}|echo b##?( )|${b##?( )}|
虽然它可能很有用,但是很难想象出一种你必须要用这种方式的情况。通常你会使用一些更适合相应任务的工具(像sed)或者直接放弃bash去使用一些像python那样的“合适的”编程语言。
10)关联数组
谈到移植到其他语言,一条重要的规则是,如果我需要用到数组,那么我会放弃bash,使用python(为此我甚至创建了一个docker container来运行一个专门的工具)
知道读到它我才知道,在bash中有关联数组
以下是演示:
$ declare -a myaa=([one]=1 [two]=2 [three]=3)$ myaa[one]=1$ myaa[two]=2$ echo $myaa$ echo ${myaa[one]}$ myaa[one]=1$ want=two$ echo ${myaa[$want]}
注意仅适用于bash4.x+版本

国产式电子教室:合美电子教室系统
电路中产生振荡现象会是什么状态?
E27、GU10接口的LED灯的解决方案及电路图
超声波塑料焊接机在作业过程中对人体有哪些危害
发动机故障灯亮是什么原因 发动机故障灯闪烁是什么问题
10种一些不太知名的bash功能你知道吗?
Qrypter仍然几乎没有得到反病毒解决方案供应商的重视
万家乐专注于改善厨房生活,力争为消费者带来优质产品
基于dsp的交流调速系统硬件接口电路设计的方法
燧原科技荣登“2023上海高新技术企业创新百强榜”
TI CC2340再续经典,信驰达无线模块助力低功耗蓝牙应用
保护接地和重复接地的区别
用Python从头实现一个神经网络来理解神经网络的原理1
常见减速电机系列有哪些?怎样找出这两个品牌的区别?
电感设计之最大磁通密度
LG发布G7 One与G7 Fit手机,搭配骁龙845处理器
工频电机改变频的危害
运算放大器的工作原理
Qt自定义窗口部件的创建
LTE专网未来将在5G网络领域中发挥重要作用