Bash的隐藏功能


72

Shell脚本通常用作胶水,用于自动化和简单的一次性任务。Bash shell /脚本语言最喜欢的“隐藏”功能有哪些?

  • 每个答案一项功能
  • 提供功能的示例和简短描述,而不仅仅是文档的链接
  • 使用粗体标题作为第一行标记功能

也可以看看:

Answers:


69

插入前一行的最终参数

alt-. 有史以来最有用的组合键,请尝试一下,由于某种原因,没人知道这一组合。

反复按它以选择较旧的最后一个参数。

当您想对刚才使用过的东西做其他事情时,这很棒。


肯定是+1。感谢您的帮助,它是如此有用,却如此隐蔽。
Alberto Zaccagni 09年

我可以使用Alt +吗?给你+2?
亚当·利斯

5
我经常使用!$,但这是更加直接和有用的。
jmanning2k 2009年

2
我觉得!$很难快速输入。我总是不得不放慢脚步,考虑将美元符号放在第二位。Alt+.更快,更容易。更不用说,您实际上在执行文本之前就已看到了该文本。
dreamlax

您也可以使用alt +-[0-9]和alt +切换参数。
Neurolabs 2010年

40

如果要在注销后保持进程运行:

disown -h <pid>

是内置的有用的bash。与不同nohup,您可以disown在已经运行的进程上运行。

首先,使用control-Z停止工作,从ps(或使用echo $!)获取pid ,使用bg将其发送到后台,然后disown与-h标志一起使用。

不要忘记为您的工作提供背景知识,否则您的工作将在注销时被杀死。


太贴心了!很多次我都想这样做。之后还可以重定向输出吗?
razzed

3
最好从jobs -l(或-p
玛丽安

恩-我曾经写过一个C程序,从本质上讲fork()exec()它的参数是守护程序。我可以轰炸炮弹,一口气跑一些东西bgexec google-chrome && exit
new123456

这不具有相同的功能screen吗?
Kasun Gajasinghe 2011年

38

手册中“扩展”部分下列出的几乎所有内容

特别是参数扩展:

$ 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

很好,那就是我如何在cmd.exe中获得%Ix = y%... :)
majkinetor


27

更多魔术组合键:

  • Ctrl+r在您的命令历史记录中开始“反向增量搜索”。在继续键入时,它将检索包含您输入的所有文本的最新命令。

  • Tab 如果您输入的单词是不含糊的,则表示该单词已完成。

  • 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 + e
    ls -N --color=tty -T 0 /home/cramey


1
alt + *(或alt-shift-8)的+1,可让您看到您将
Marcus Downing 2010年

我打开了显示所有模棱两可的功能,以防止两次按下Tab键。
乍得·高辛2011年

24

取回历史命令和参数

可以使用!运算符有选择地访问先前的命令和参数。当您使用长路径时,这非常有用。

您可以使用来检查最后的命令history

您可以将以前的命令用作命令!<n>n的索引history,负数从历史记录中的最后一条命令开始倒数。

ls -l foo bar
touch foo bar
!-2

您可以将先前的参数与一起使用!:<n>,命令为零,参数> = 1。

ls -l foo
touch !:2
cp !:1 bar

您可以将两者结合 !<n>:<m>

touch foo bar
ls -l !:1 !:2
rm !-2:1 !-2:2
!-2

您还可以使用参数范围 !<n>:<x>-<y>

touch boo far
ls -l !:1-2

其他!特殊修饰符是:

  • * 对于所有的论点

    ls -l foo bar
    ls !*
    
  • ^对于第一个参数(!:1== !^

  • $ 最后一个论点

    ls -l foo bar
    cat !$ > /dev/null
    

5
^ R键盘快捷键也非常方便
马克·贝克

5
我也喜欢alt-^(美国键盘上的alt-shift-6)。它扩展了!! 2之类的历史记录序列,因此您可以在运行命令之前查看该命令将要执行的操作。
道格(Doug)

1
代替$!尝试输入ESC +。最后一个参数将出现在光标下方。
Philippe A.


19

SECONDS=0; sleep 5 ; echo "that took approximately $SECONDS seconds"

每次引用此参数时,返回自Shell调用以来的秒数。如果将值分配给SECONDS,则后续引用返回的值是分配以来的秒数加上分配的值。如果未设置SECONDS,则即使随后将其重置,它也会丢失其特殊属性。


17

这是我的最爱之一。这会将制表符补全设置为不区分大小写。这对于快速键入目录路径非常有用,尤其是在Mac上(默认情况下文件系统不区分大小写)。我把它放在.inputrc我的主文件夹中。

set completion-ignore-case on

1
我对此一无所知,谢谢。这在我的〜/ .inputrc中已经被注释掉了。我将其打开并显示所有模棱两可的内容。
乍得·高辛2011年

16

特殊变量随机:

if [[ $(($RANDOM % 6)) = 0 ]]
    then echo "BANG"
else
    echo "Try again"
fi   

13
#[$ [$ RANDOM%6] == 0] && rm -rf / || 回声“你活着” :)
凯文(Kevin)2010年

无需$在算术评估内贴标;无需单独的评估和测试:if (( RANDOM % 6 == 0 )); then echo "BANG"; else echo "Try again"; fi甚至更短:(( RANDOM % 6 )) && echo "Try again" || echo "BANG"
manatwork

13

正则表达式处理

最新的bash版本具有正则表达式匹配功能,因此您可以执行以下操作:

if [[ "mystring" =~ REGEX ]] ; then  
    echo match
fi

REGEX是原始正则表达式,格式为man re_format描述。

来自方括号的任何部分的匹配项都存储在BASH_REMATCH数组中,从元素1开始(元素0是整个匹配的字符串),因此您也可以使用它进行正则表达式支持的解析。


不必将正则表达式用引号引起来,感觉有点奇怪。。。
dreamlax

13

Ctrlx Ctrle

这会将当前命令加载到变量VISUAL中定义的编辑器中。这对于长命令(如此处列出的某些命令)确实很有用。

要将vi用作编辑器:

export VISUAL=vi

set -o vi然后按Esc键即可进行内联编辑,普通的'v'将命令拖入完整的vi编辑器中。
斯蒂芬·P

13

快速和肮脏的拼写错误纠正(对于通过慢速连接的长命令特别有用,因为使用命令历史记录并滚动查看它会很可怕):

$ cat /proc/cupinfo
cat: /proc/cupinfo: No such file or directory
$ ^cup^cpu

也试试 !:s/old/new一次用上一个命令中的old替换new。

如果您想替换许多事件,可以使用 !:gs/old/new

您可以将gsands命令用于任何历史事件,例如

!-2:s/old/new

在倒数第二个命令old中用new(一次)替换。


1
有什么办法可以找到有关此功能或类似功能的更多信息?谷歌搜索^ foo ^ bar并不令人满意:)
Tetha

3
Java中的事件指示符和修饰符man bash。尝试!:s/old/new一次用上一个命令中的old替换new。如果您想替换许多事件,可以使用进行全局替换!:gs/old/new。这可能与詹姆士的帖子( stackoverflow.com/questions/211378/hidden-features-of-bash/…),例如:(用上!$:s/old/new一个命令的最后一个参数中的old替换new),!-2:0:gs/a/s !-2*(用倒数第二个命令名称中带有s的a,并添加倒数第二个命令的所有参数)。祝好运!
Iceland_jack

10

这是我的两个最爱:

要检查没有实际执行脚本的语法,请使用:

bash -n script.sh

返回上一个目录(是的,我知道已被推送和弹出,但是这样更快)

cd -

3
如果您忘记将目录压入堆栈,但仍想返回该目录,则“ cd-”具有工作优势。
temp2290

8

使用中置布尔运算符

考虑以下简单情况:

if [ 2 -lt 3 ]
    then echo "Numbers are still good!"
fi

-lt看起来有点丑。不是很现代。如果在布尔表达式周围使用双括号,则可以使用普通的布尔运算符!

if [[ 2 < 3 ]]
    then echo "Numbers are still good!"
fi

3
这不是Bash的功能,而是一个外部程序:是的,“ [[”是一个独立程序。
Mathieu Garstecki

2
madmath:我想您会发现[通常是要测试的符号链接或硬链接,而[[是内置的shell。它需要由shell解析,否则<看起来像输入重定向。
格雷格(Greg Hewgill)

5
不,“ [”是一个独立程序。'[['不是
Vinko Vrsalovic

1
$ type [[[[是一个shell关键字$,其中[[$#没有输出
Mark A. Nicolosi,

显然,SO不喜欢注释中的换行符,希望它不太难解析。那是在Ubuntu上使用Bash 3.2.39,BTW。
Mark A. Nicolosi

8

数组:

#!/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脚本编制指南》


8

在显示bash提示之前运行命令

在环境变量“ PROMPT_COMMAND”中设置命令,它将在每次提示前自动运行。例:

[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中,然后坐下来观察混乱的发生。


8

bashman页面上的魔术键组合:

  • Ctrl+aCtrl+分别e将光标移动到当前行的开头和结尾。

  • Ctrl+tAlt+t将光标和字符和单词与当前光标和字符移到前面,然后向前移动光标。

  • Alt+uAlt+l将当前单词(从光标到结尾)转换为大写和小写。

    提示:Alt+,然后按以下任一命令转换当前单词的开头


奖励man提示:

  • 查看时 man页面时,/用于在页面内搜索文本。使用n提前跳转到下一场比赛或N前一个比赛。

  • man利用其格式来加快页面中特定命令或子节的搜索速度:

    o不用键入/history expansion来查找该部分,而是尝试/^history使用插入号(^)查找以“历史记录”开头的行。

    o尝试/   read用一些前导空格搜索该内置命令。内置文件总是缩进man页面中。


7

export TMOUT=$((15*60))

闲置15分钟后终止bash,将其设置为0以禁用。我通常将它放在我的根帐户上的〜/ .bashrc中。在管理您的邮箱时非常方便,您可能会忘记在离开终端之前注销。


7

撤消

C-S-- 控制移位减撤消键入操作。

杀/ Yan

任何删除操作C-w(删除前一个单词),C-k(删除到行尾),C-u(删除到行首)等...将其已删除的文本复制到kill环,您可以使用以下命令粘贴最后一个kill:C-y并循环遍历(和从中粘贴已删除项目的环Alt-y


7

通过设置FIGNORE变量,可以在制表符完成时忽略某些文件。

例如,如果您有一个Subverion版本库,并且想更轻松地导航

export FIGNORE=".svn"

现在您可以cd不受.svn目录的限制。



5

支撑扩展

使用{x,y,z}的标准扩展:

$ echo foo{bar,baz,blam}
foobar foobaz fooblam
$ cp program.py{,.bak}  # very useful with cp and mv

用{x..y}扩展序列:

$ 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

4

我最近读了《Csh编程被认为有害》,其中包含以下惊人的瑰宝:

考虑管道:

A | B | C

您想知道C的状态,这很容易:它在$?或csh中的$ status中。但是,如果您希望从A获得它,那么您就不走运了-如果您在csh中,那就是。在Bourne shell中,您可以获取它,尽管这样做有些棘手。在将dd的stderr放入grep -v管道中以消除记录输入/输出噪声的情况下,我必须做些事情,但是必须返回dd的退出状态,而不是grep的退出状态:

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;

19
您要使用PIPESTATUS变量,该变量是管道中每个命令的退出状态的数组。$ {PIPESTATUS [0]}将是您想要的。
史蒂夫·贝克

史蒂夫,我从不知道-在这里发布答案!(如果您愿意,我会予以投票:)
马克·贝克

4

截断文件(清零文件)的内容

> file

具体来说,这在截断日志文件时非常有用,当该文件被另一个进程打开时,该进程仍可能写入该文件。


为防止您意外截断文件,set -o noclobber。然后,您需要使用>| file截断文件。
格伦·杰克曼

4

并不是真正的功能,而是一个方向:我在commandlinefu.com上发现了许多“隐藏的功能”,秘密和各种bash有用性。这个答案有很多评分最高的答案,我是在该网站上学到的:)


4

另一个小: Alt+#

注释掉当前行并将其移到历史记录缓冲区中。

因此,在组装命令行时,您需要发出临时命令来查找文件,例如,只需按alt +#,发出另一条命令,进入历史记录,取消注释并继续。


4

代替大括号do,并done在for循环

For循环体通常位于do...done(仅作为示例):

for f in *;
do
    ls "$f";
done

但是我们可以使用大括号使用C样式:

for f in *; {
    ls "$f";
}

我认为这看起来要比do...done我好,我更喜欢这个。我尚未在任何Bash文档中找到此功能,因此这确实是一个隐藏功能。


3

C样式数字表达式:

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 ""

3

这些属性是我的最爱之一。

export HISTCONTROL=erasedups
export HISTSIZE=1000

第一个确保bash不会多次记录命令,这将真正提高history的实用性。另一个将历史记录大小从默认的100扩展到1000。我实际上在我的计算机上将其设置为10000。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.