Bash的隐藏功能

时间:2008-10-17 08:14:03

标签: bash shell scripting hidden-features

Shell脚本通常用作粘合剂,用于自动化和简单的一次性任务。您最喜欢的Bash shell /脚本语言的“隐藏”功能是什么?

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

另见:

43 个答案:

答案 0 :(得分:69)

插入前一行的最终参数

alt - 有史以来最有用的组合键,尝试看看,由于某些原因,没有人知道这个。

反复按此按钮选择较旧的最后一个参数。

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

答案 1 :(得分:40)

如果您希望在注销后继续运行流程:

disown -h <pid>

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

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

不要忘记记录你的工作,否则当你退出时就会被杀死。

答案 2 :(得分:38)

手册

中EXPANSION部分下列出的几乎所有内容

特别是参数扩展:

$ 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

答案 3 :(得分:35)

我的最爱:

sudo !!

使用sudo重新运行上一个命令。

答案 4 :(得分:27)

更多魔术键组合:

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

  • Tab 完成您到目前为止输入的单词,如果它是明确的。

  • 标签 标签列出了您目前输入的字词的所有完成情况。

  • Alt + * 插入所有可能的完成情况,例如,如果您刚刚输入潜在的带通配符的破坏性命令:

    rm -r source/d*.c Alt + *
    rm -r source/delete_me.c source/do_not_delete_me.c

  • Ctrl + Alt + e 在当前行上执行别名,历史记录和shell扩展。换句话说,当前行被重新显示,因为它将由shell处理:

    ls $HOME/tmp Ctrl Alt + e
    ls -N --color=tty -T 0 /home/cramey

答案 5 :(得分:24)

取回历史记录命令和参数

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

您可以使用history检查上一个命令。

您可以使用!<n> n之前的命令history ls -l foo bar touch foo bar !-2 中的命令索引,负数从历史记录中的最后一个命令向后计数。

!:<n>

您可以将以前的参数与ls -l foo touch !:2 cp !:1 bar 一起使用,零是命令,&gt; = 1是参数。

!<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 获取最后一个参数

    {{1}}

答案 6 :(得分:20)

我喜欢-x功能,允许查看脚本中发生了什么。

bash -x script.sh 

答案 7 :(得分:19)

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

  

<强>秒

     

每次参数都是   引用,秒数   因为返回了shell调用。   如果为SECONDS分配了值,   随后返回的值   references是秒数   因为赋值加上了值   分配。如果没有设置SECONDS,那就是   失去其特殊属性,即使   它随后被重置。

答案 8 :(得分:17)

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

set completion-ignore-case on

答案 9 :(得分:16)

特殊变量random:

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

答案 10 :(得分:13)

正则表达式处理

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

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

其中REGEX是man re_format描述的格式的原始正则表达式。

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

答案 11 :(得分:13)

Ctrl x Ctrl e

这会将当前命令加载到变量VISUAL中定义的编辑器中。这对于像这里列出的一些长命令非常有用。

使用vi作为编辑器:

export VISUAL=vi

答案 12 :(得分:13)

快速&amp;拼写错误的纠正(对于使用命令历史记录并滚动浏览它的慢速连接的长命令尤其有用):

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

同时尝试使用上一个命令中的old替换old !:s/old/new一次。

如果要替换多次出现,可以使用!:gs/old/new进行全局替换。

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

!-2:s/old/new

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

答案 13 :(得分:10)

这是我最喜欢的两个:

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

bash -n script.sh

回到最后一个目录(是的,我知道pushd和popd,但这更快)

cd -

答案 14 :(得分:8)

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

在“PROMPT_COMMAND”env变量中设置一个命令,它将在每个提示之前自动运行。 例如:

[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

对于下一个4月的傻瓜,将“export PROMPT_COMMAND = cd”添加到某人的.bashrc然后坐下来观看混乱的展开。

答案 15 :(得分: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脚本编写内容)的更多详细信息,请参见Advanced Bash-Scripting Guide

答案 16 :(得分:8)

来自bash man页面的魔术键组合:

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

  • Ctrl + t Alt + t 转置光标前的字符和单词当前的那个,然后向前移动光标。

  • Alt + u Alt + l 转换当前单词(从光标到结束)大写和小写。

    提示: Alt + - 后跟其中任何一个命令转换当前的开头字。


奖金man提示:

  • 在查看man页面时,使用 / 搜索页面中的文本。使用 n 跳转到下一场比赛,或使用 N 进行上一场比赛。

  • 利用其格式加快搜索man页面中的特定命令或子部分:

    o而不是键入 / history expansion 来查找该部分,尝试 / ^ history ,使用插入符号(^)仅查找< em>开始与“历史。”

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

答案 17 :(得分:8)

使用中缀布尔运算符

考虑简单的if:

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

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

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

答案 18 :(得分:7)

export TMOUT=$((15*60))

空闲时间15分钟后终止bash,设置为0表示禁用。我通常把它放在我的root帐户上的〜/ .bashrc中。管理你的盒子很方便,你可能会忘记在离开终端之前退出。

答案 19 :(得分:7)

撤消

C-S - 控制班次减号撤消键入操作。

Kill / Yank

任何删除操作 Cw (删除前一个单词), Ck (删除到行尾), Cu (删除到行开头) )等...将其删除的文本复制到kill ring,你可以粘贴最后一个kill: Cy 并使用 Alt-y循环(并粘贴)已删除项目的环

答案 20 :(得分:7)

通过设置FIGNORE变量,您可以在标签完成时忽略某些文件。

例如,如果您有一个subverion repo并且想要更轻松地导航

export FIGNORE=".svn"

现在您可以cd而不被.svn目录阻止。

答案 21 :(得分:5)

使用算术:

if [[ $((2+1)) = $((1+2)) ]]
    then echo "still ok"
fi

答案 22 :(得分: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

答案 23 :(得分:4)

截断文件内容(归零文件)

> file

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

答案 24 :(得分:4)

在for循环中代替dodone的大括号

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

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

但我们可以使用大括号的C风格:

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

我认为这看起来比do...done更好,我更喜欢这个。我还没有在任何Bash文档中找到它,所以这真的是一个隐藏的功能。

答案 25 :(得分:4)

我最近阅读了包含这个令人震惊的宝石的Csh Programming Considered Harmful

  

考虑管道:

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;

答案 26 :(得分:4)

另一个小小的: 替代 +

注释掉当前行并将其移入历史缓冲区。

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

答案 27 :(得分:4)

不是一个功能而是一个方向:我在commandlinefu.com找到了许多“隐藏的功能”,秘密和各种bash实用性。许多评价最高的答案,我在那个网站上学到了它们:)

答案 28 :(得分:3)

set -o vi,以便对命令历史记录以及当前键入的命令进行类似vi的编辑。

答案 29 :(得分:3)

轻松在多个目录之间移动

不是隐藏功能,但比pushd更灵活,需要类似堆栈的导航。

a() { alias $1=cd\ $PWD; }

cd某处并输入a 1。稍后只需输入1即可返回该目录。

答案 30 :(得分: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 ""

答案 31 :(得分:3)

这些属性是我的另一个属性。

export HISTCONTROL=erasedups
export HISTSIZE=1000

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

答案 32 :(得分:3)

我经常使用的是!$来引用最后一个命令的最后一个字:

$ less foobar.txt
...
# I dont want that file any more
$ rm !$

答案 33 :(得分:2)

Bash有变量间接:

$ foo=bar
$ baz=foo
$ echo ${!baz}
bar

答案 34 :(得分:2)

我有一个别名r='fc-s',我发现它在某些有限的情况下非常有用。要运行最后一个命令,只需键入r并按Enter键即可。当然,这本身并不是很有用,因为向上箭头做同样的事情。但您可以使用r运行带有替换的上一个命令。假设您的最后一个命令是编译某个文件的长命令:

$ gcc -c <file_name>.c <lots of options> -o <file_name>.o

现在您要编译具有相同选项的另一个文件并具有相应的.o文件:

$ r <file_name>=<new_file>

会做到的。您不必使用向上箭头,导航到正确的位置,然后手动替换它们。这可以重复多次,因此您可以执行以下操作:

$ r <new_file>=<other_file>

当然,对于这样的事情,你有makefile,但我希望我已经证明别名是有用的。

我不需要使用这个别名,但有时候我很高兴我有这个别名!

答案 35 :(得分:2)

正如其他人所提到的, Ctrl - r 非常适合退回命令历史记录。但是,如果你想要在经过一个或几个步骤之后继续前进怎么办?这就是 Ctrl - s 派上用场的地方。但是,它通常映射到XOFF(中断数据流)。由于我们不使用慢速串行终端,因为它不再有用,你可以用以下方式关闭该映射:

stty -ixon

~/.bashrc文件中。

这也使 Ctrl - q 可用,这通常是 Ctrl - v 的重复(引用 - 插入,允许您插入文字控制字符)。我有 Ctrl - q 映射到menu-complete,当重复按下时会逐步完成完成。我想将 Tab 设置为常规完成。

您可以通过将此行添加到~/.inputrc文件来将 Ctrl - q 设置为菜单完成:

"\C-q": menu-complete

答案 36 :(得分:2)

此处字符串<<<)。 Bash手册给出了这样的描述:

  

单词被扩展并在其标准输入上提供给命令。

示例:

$ cat<<<"$(( 10*3+1 )) nice isn't it?"
31 nice isn't it?

答案 37 :(得分:1)

使用'let'内置bash命令进行基本算术

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的一部分)。

FP=`echo "scale=4; 10 / 3" | bc` # FP="3.3333"

答案 38 :(得分:1)

使用&lt;(cmd ...)或&gt;(cmd ...)

进行替换

在每种形式中,执行cmd时,其输入或输出连接到FIFO,并且在命令行上替换该FIFO的路径:

$ 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

例如,比较两个网站而不保存中间文件:

$ diff <(curl -s http://tldp.org/LDP/abs/html/) <(curl -s http://www.redhat.com/mirrors/LDP/LDP/abs/html/)

如果你有一个命令将文件名作为输入,但不接受' - '表示stdout,你可以欺骗它:

$ do_thingee --log -
error: can't open log file: '-'
$ do_thingee --log >(cat)
do_thingee v0.2
initializing things
processing 4 things
done

答案 39 :(得分:1)

特殊套接字文件名:/ dev / tcp / HOST / PORT和/ dev / udp / HOST / PORT

从日间服务器(端口13)读取:

$ cat < /dev/tcp/utcnist.colorado.edu/13

55786 11-08-13 03:34:21 50 0 0 172.3 UTC(NIST) *

这与tcpserver结合使用非常有用。

如果您无权访问wget或curl,则来自http://thesmithfam.org/blog/2006/05/23/bash-socket-programming-with-devtcp-2/的更高级示例:

$ exec 3<>/dev/tcp/www.google.com/80 # hook up to file desc 3
$ echo -e "GET / HTTP/1.1\n\n" >&3   # send the HTTP request
$ cat <&3                            # read the HTTP response

答案 40 :(得分:0)

嵌入式命令替换:

  

主机名&amp;&amp;挖+短$(主机名)&amp;&amp; dig + short -x $(挖掘+短期$(主机名))

此命令适用于检查邮件服务器上的RDNS。 :P

答案 41 :(得分:0)

快速搜索历史记录

以下提供类似历史搜索的tcsh,方便易用。

将以下行添加到~/.inputrc/etc/inputrc

$ cat ~/.inputrc
"\e[A": history-search-backward
"\e[B": history-search-forward

您可能希望使用意外较少的组合键,例如Esc + p。如果是这种情况,请使用

"\ep": history-search-backward
"\en": history-search-forward

然后,只需键入前几个字母,然后按UpArrow键。它将显示以给定字母开头的最新命令。

例如:

输入grep,UpArrow。 它会显示grep -ri myText .

之类的内容

答案 42 :(得分:0)

http://linuxconfig.net/manual-howto/key-combinations-in-bash.html

中获取有关Bash中键组合的更多信息