Hidden features of Bash
shell脚本通常用作胶水,用于自动化和简单的一次性任务。您最喜欢的bash shell/脚本语言的"隐藏"特性是什么?
- 每个答案一个功能
- 给出功能的示例和简短描述,而不仅仅是指向文档的链接
- 用粗体标题作为第一行标记功能
参见:
- C的隐藏特征
- C的隐藏特征#
- C++的隐藏特性
- 德尔菲的隐藏特征
- Python的隐藏特征
- Java的隐藏特性
- javascript的隐藏特性
- 红宝石的隐藏特征
- PHP的隐藏功能
- Perl的隐藏特性
- VB.NET的隐藏功能
插入前一行的最终参数
alt-.是有史以来最有用的组合键,试试看,不知为什么没有人知道这个组合键。
一次又一次地按它以选择旧的最后一个参数。
很好,当你想对刚才用过的东西做点别的事情的时候。
如果要在注销后保持进程运行:
是一个内置的有用的bash。与
首先,用control-z停止工作,从
别忘了做你工作的背景,否则你注销后会被杀的。
手册扩展部分列出的几乎所有内容
尤其是参数展开:
1 2 3 4 5 6 7 8 9 | $ I=foobar $ echo ${I/oo/aa} #replacement faabar $ echo ${I:1:2} #substring oo $ echo ${I%bar} #trailing substitution foo $ echo ${I#foo} #leading substitution bar |
我最喜欢的是:
1 | sudo !! |
用sudo重新运行上一个命令。
更多魔术组合:
ctrl+r通过命令历史记录开始"反向增量搜索"。当您继续键入时,它将检索包含您输入的所有文本的最新命令。
t完成了迄今为止输入的单词,如果它不含糊的话。
TAB TAB列出了迄今为止键入的单词的所有补全。
alt+*插入所有可能的完成操作,这特别有用,例如,如果您刚刚输入了一个具有潜在破坏性的命令,使用通配符:
rm -r source/d*.c alt+*rm -r source/delete_me.c source/do_not_delete_me.c ctrl+alt+e在当前行上执行别名、历史记录和外壳扩展。换句话说,当前行将重新显示,因为它将由shell处理:
ls $HOME/tmp ctrl alt+els -N --color=tty -T 0 /home/cramey
返回历史记录命令和参数
可以使用
您可以使用
您可以使用以前的命令,其中
1 2 3 | ls -l foo bar touch foo bar !-2 |
您可以将前面的参数与
1 2 3 | ls -l foo touch !:2 cp !:1 bar |
你可以和
1 2 3 4 | touch foo bar ls -l !:1 !:2 rm !-2:1 !-2:2 !-2 |
也可以使用参数范围
1 2 | touch boo far ls -l !:1-2 |
其他
* 表示所有的论点1
2ls -l foo bar
ls !*第一个论点的
^ (!:1 ==!^ )最后一个论点
1
2ls -l foo bar
cat !$ > /dev/null
我喜欢-x特性,允许查看脚本中的内容。
1 | bash -x script.sh |
SECONDS
Each time this parameter is
referenced, the number of seconds
since shell invocation is returned.
If a value is assigned to SECONDS,
the value returned upon subsequent
references is the number of seconds
since the assignment plus the value
assigned. If SECONDS is unset, it
loses its special properties, even if
it is subsequently reset.
这是我的最爱之一。这将选项卡完成设置为不区分大小写。它非常适合快速输入目录路径,特别是在默认情况下文件系统不区分大小写的Mac上。我把这个放在我的文件夹里。
1 | set completion-ignore-case on |
特殊变量随机:
1 2 3 4 5 | if [[ $(($RANDOM % 6)) = 0 ]] then echo"BANG" else echo"Try again" fi |
快速修正输入错误(特别适用于使用命令历史记录和滚动命令会很糟糕的慢速连接上的长命令):
1 2 3 | $ cat /proc/cupinfo cat: /proc/cupinfo: No such file or directory $ ^cup^cpu |
也可以尝试一下
如果要替换多个事件,可以使用
您可以在任何历史事件中使用
1 | !-2:s/old/new |
在第二个命令到最后一个命令中用
正则表达式处理
最近发布的bash具有正则表达式匹配功能,因此可以执行以下操作:
1 2 3 | if [["mystring" =~ REGEX ]] ; then echo match fi |
其中regex是一个原始的正则表达式,格式由man re-u格式描述。
任何带括号部分的匹配项都存储在bash-rematch数组中,从元素1开始(元素0是整个匹配字符串),因此您也可以使用它进行regex支持的解析。
CtrLCtrLBakBd
这将把当前命令加载到变量visual中定义的编辑器中。这对于长命令非常有用,比如这里列出的一些命令。
要使用vi作为编辑器:
1 | export VISUAL=vi |
以下是我的两个最爱:
要在不真正执行脚本的情况下检查语法,请使用:
1 | bash -n script.sh |
回到最后一个目录(是的,我知道pushd和popd,但这更快)
1 | cd - |
数组:
1 2 3 4 5 6 7 8 9 10 | #!/bin/bash array[0]="a string" array[1]="a string with spaces and "quotation" marks in it" array[2]="a string with spaces, "quotation marks" and (parenthesis) in it" echo"There are ${#array[*]} elements in the array." for n in"${array[@]}"; do echo"element = >>${n}<<" done |
有关阵列(以及其他高级bash脚本编写工具)的更多详细信息,请参阅《高级bash脚本编写指南》。
bash
ctrl+a和ctrl+e分别将光标移动到当前行的开头和结尾。
ctrl+t和alt+t将光标前面的字符和单词与当前字符和单词进行换位,然后向前移动光标。
alt+u和alt+l将当前单词(从光标到结尾)转换为大写和小写。
提示:按alt+&ndash;,然后按以下任一命令转换当前单词的开头。
奖金
在查看
man 页时,使用/搜索页面内的文本。使用n向前跳到下一个匹配,或使用n向前跳到上一个匹配。利用
man 页中的特定命令或子节的格式,加快搜索速度:o不要键入/history expansion来查找该节,而是尝试/^ history,使用插入符号(
^ 来查找仅以"history"开头的行。o尝试使用/ ;read(带有一些前导空格)来搜索该内置命令。内置内容总是缩进到
man 页中。
使用中缀布尔运算符
如果:
1 2 3 | if [ 2 -lt 3 ] then echo"Numbers are still good!" fi |
那-看起来有点难看。不是很现代。如果在布尔表达式周围使用双括号,则可以使用普通布尔运算符!
1 2 3 | if [[ 2 < 3 ]] then echo"Numbers are still good!" fi |
在显示bash提示之前运行命令
在"prompt_command"env变量中设置一个命令,它将在每次提示之前自动运行。例子:
1 2 3 4 5 6 | [lsc@home]$ export PROMPT_COMMAND="date" Fri Jun 5 15:19:18 BST 2009 [lsc@home]$ ls file_a file_b file_c Fri Jun 5 15:19:19 BST 2009 [lsc@home]$ ls |
对于下一个愚人节,将"export prompt_command=cd"添加到某人的.bashrc然后坐下来观察混乱的展开。
空闲15分钟后终止bash,设置为0以禁用。我通常把这个放在根帐户的~/.bashrc上。它在管理您的箱子时很方便,您可能会忘记在离开终端前注销。
撤消
c-s--control shift minusundo es typing actions.
杀戮/要害任何删除操作c w(删除前一个字)、c k(删除到行尾)、c u(删除到行首)等…将删除的文本复制到kill环,您可以使用:c y粘贴最后一个kill,并使用alt y循环(并从中粘贴)已删除项目的环。
通过设置
例如,如果您有一个子周期回购,并且您希望更轻松地进行导航,请执行以下操作
1 | export FIGNORE=".svn" |
现在您可以在不被
撑杆展开
带x,y,z的标准扩展:
1 2 3 | $ echo foo{bar,baz,blam} foobar foobaz fooblam $ cp program.py{,.bak} # very useful with cp and mv |
用X..Y进行序列扩展:
1 2 3 4 | $ echo {a..z} a b c d e f g h i j k l m n o p q r s t u v w x y z $ echo {a..f}{0..3} a0 a1 a2 a3 b0 b1 b2 b3 c0 c1 c2 c3 d0 d1 d2 d3 e0 e1 e2 e3 f0 f1 f2 f3 |
使用算术:
1 2 3 | if [[ $((2+1)) = $((1+2)) ]] then echo"still ok" fi |
不是一个特性,而是一个方向:我在commandlinefu.com上发现了许多"隐藏特性"、秘密和各种bash的有用性。许多对这些答案评价最高的答案,我都是在那个网站上学到的:)
截断文件的内容(归零文件)
1 | > file |
具体地说,当文件被另一个进程打开时,这对于截断日志文件非常有用,而该进程仍可能写入该文件。
for循环中用括号代替
1 2 3 4 | for f in *; do ls"$f"; done |
但是我们可以使用大括号的C样式:
1 2 3 | for f in *; { ls"$f"; } |
我觉得这个比
另一个小的:alt+
注释当前行并将其移动到历史缓冲区。
因此,当您组装命令行时,需要发出一个临时命令,例如查找一个文件,只需点击alt+,发出另一个命令,进入历史记录,取消注释并继续。
我最近读到的CSH编程被认为是有害的,其中包含了这个惊人的宝石:
Consider the pipeline:
1 | A | B | C |
You want to know the status of C, well, that's easy: it's in $?, or
$status in csh. But if you want it from A, you're out of luck -- if
you're in the csh, that is. In the Bourne shell, you can get it, although
doing so is a bit tricky.
Here's something I had to do where I ran dd's
stderr into a grep -v pipe to get rid of the records in/out noise, but had
to return the dd's exit status, not the grep's:
1 2 3 4 5 6 | device=/dev/rmt8 dd_noise='^[0-9]+\+[0-9]+ records (in|out)$' exec 3>&1 status=`((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) | egrep -v"$dd_noise" 1>&2 3>&- 4>&-) 4>&1` exit $status; |
C样式数值表达式:
1 2 3 4 5 6 7 8 9 | let x="RANDOM%2**8" echo -n"$x = 0b" for ((i=8; i>=0; i--)); do let n="2**i" if (( (x&n) == n )); then echo -n"1" else echo -n"0" fi done echo"" |
在多个目录之间轻松移动
不是隐藏的功能,但比需要类似堆栈的导航的pushd更灵活。
1 | a() { alias $1=cd\ $PWD; } |
我经常使用的一个是!$指最后一个命令的最后一个字:
1 2 3 4 | $ less foobar.txt ... # I dont want that file any more $ rm !$ |
这些属性是我的另一个最爱。
1 2 | export HISTCONTROL=erasedups export HISTSIZE=1000 |
第一种方法确保bash不会多次记录命令,这将真正提高
正如其他人所提到的,ctrl r对于返回命令历史记录非常有用。但如果你想在走了一步或几步太多之后继续前进呢?这就是CtrL Sakbd的用武之地。但是,它通常被映射到xoff(中断数据流)。因为我们不再使用慢速串行终端,所以这不再有用,您可以通过以下方式关闭映射:
1 | stty -ixon |
在你的
这也使得ctrl q可用,这通常是ctrl v(带引号的插入,允许您插入文字控制字符)的副本。我已经将ctrl q映射到菜单完成,当重复按下时,该菜单将逐步完成。我喜欢将tabkbbkbd设置为常规完成。
您可以将ctrl q设置为菜单完成,方法是将该行添加到您的
1 | "\C-q": menu-complete |
bash具有可变的间接寻址:
1 2 3 4 | $ foo=bar $ baz=foo $ echo ${!baz} bar |
我有一个别名
1 | $ gcc -c <file_name>.c <lots of options> -o <file_name>.o |
现在,您希望使用相同的选项编译另一个文件,并拥有相应的
1 | $ r <file_name>=<new_file> |
会做的。您不必使用向上箭头,导航到正确的位置,然后手动替换它们。这可以重复多次,因此您可以接下来执行此操作:
1 | $ r <new_file>=<other_file> |
当然,对于这样的事情,您有makefiles,但我希望我已经证明了别名是有用的。
我不太需要使用这个别名,但是有很多次我很高兴我有这个别名!
这里是字符串(
The word is expanded and supplied to the command on its standard input.
例子:
1 2 | $ cat<<<"$(( 10*3+1 )) nice isn't it?" 31 nice isn't it? |
对基本算术使用"let"内置bash命令
1 2 3 4 | A=10 let B="A * 10 + 1" # B=101 let B="B / 8" # B=12, let does not do floating point let B="(RANDOM % 6) + 1" # B is now a random number between 1 and 6 |
要执行浮点计算,可以使用"bc"命令(bash的任何部分)。
1 | FP=`echo"scale=4; 10 / 3" | bc` # FP="3.3333" |
用<(Cmd…)或>(Cmd…)替换进程
在每种形式中,命令执行时其输入或输出连接到一个FIFO,并在命令行上替换到该FIFO的路径:
1 2 | $ echo A file to read: <(cat), a file to write to: >(cat) A file to read: /dev/fd/63, a file to write to: /dev/fd/62 |
例如,在不保存中间文件的情况下比较两个网站:
1 | $ diff <(curl -s http://tldp.org/LDP/abs/html/) <(curl -s http://www.redhat.com/mirrors/LDP/LDP/abs/html/) |
如果您有一个将文件名作为输入的命令,但不接受"-"表示stdout,则可以对其进行欺骗:
1 2 3 4 5 6 7 | $ do_thingee --log - error: can't open log file: '-' $ do_thingee --log >(cat) do_thingee v0.2 initializing things processing 4 things done |
特殊套接字文件名:/dev/tcp/host/port和/dev/udp/host/port
从日间服务器(端口13)读取:
1 2 3 | $ cat < /dev/tcp/utcnist.colorado.edu/13 55786 11-08-13 03:34:21 50 0 0 172.3 UTC(NIST) * |
这对于与tcpserver结合使用非常有用。
http://thesmithfam.org/blog/2006/05/23/bash-socket-programming-with-devtcp-2/提供了一个更高级的示例,如果您无法访问wget或curl:
1 2 3 4 5 | $ exec 3<>/dev/tcp/www.google.com/80 # hook up to file desc 3 $ echo -e"GET / HTTP/1.1 ">&3 # send the HTTP request $ cat <&3 # read the HTTP response |
嵌入式命令替换:
hostname && dig +short $(hostname) && dig +short -x $(dig +short $(hostname))
此命令适用于检查邮件服务器上的RDN。P
快速历史搜索
下面给出了一个类似tcsh的历史搜索,既方便又简单。
将以下行添加到
1 2 3 | $ cat ~/.inputrc "\e[A": history-search-backward "\e[B": history-search-forward |
您可能希望使用较少意外的组合键,如
1 2 | "\ep": history-search-backward "\en": history-search-forward |
然后,只需键入前几个字母,然后按向上箭头键。它将显示以给定字母开头的最新命令。
前任:
在http://linuxconfig.net/manual-howto/key-combinations-in-bash.html中获取有关bash中键组合的更多信息