Bash 的隐藏功能
Posted
技术标签:
【中文标题】Bash 的隐藏功能【英文标题】:Hidden features of Bash 【发布时间】:2010-09-17 16:53:56 【问题描述】:Shell 脚本通常用作粘合剂,用于自动化和简单的一次性任务。您最喜欢 Bash shell/脚本语言的哪些“隐藏”功能?
每个答案一个功能 提供功能示例和简短说明,而不仅仅是文档链接 使用粗体标题作为第一行标记功能另见:
Hidden features of C Hidden features of C# Hidden features of C++ Hidden features of Delphi Hidden features of Python Hidden features of Java Hidden features of javascript Hidden features of Ruby Hidden features of php Hidden features of Perl Hidden features of VB.Net【问题讨论】:
【参考方案1】:插入前一行的最后一个参数
alt-. 有史以来最有用的组合键,试试看,不知为何没人知道这个组合键。
一次又一次地按下它以选择较旧的最后一个参数。
当您想对刚才使用的东西做其他事情时非常棒。
【讨论】:
绝对+1。感谢这个,非常有用但又如此隐蔽。 我可以使用 Alt+.给你+2? 我是 !$ 的常客,但这更直接更有用。 我发现!$
很难快速输入。我总是不得不放慢脚步,考虑把美元符号放在第二位。 Alt
+.
更快更容易。更不用说,您实际上可以在执行之前看到文本。
你也可以用alt+-[0-9]切换参数,然后alt+。【参考方案2】:
如果您想在注销后保持进程运行:
disown -h <pid>
是一个有用的内置 bash。与nohup
不同,您可以在已经运行的进程上运行disown
。
首先,使用 control-Z 停止工作,从 ps
获取 pid(或使用 echo $!
),使用 bg
将其发送到后台,然后使用带有 -h 标志的 disown
。
不要忘记后台你的工作,否则当你注销时它会被杀死。
【讨论】:
太甜了!很多次我都想这样做。之后您还可以重定向输出吗? 最好从jobs -l
(或-p
)获取PID
Eh - 我曾经写过一个 C 程序,本质上是 fork()
和 exec()
它的参数,本质上是一个守护进程。我可以轰炸外壳并一口气运行一些东西bgexec google-chrome && exit
。
这不是和screen
的功能一样吗?【参考方案3】:
手册中 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
【讨论】:
很好,这就是我在 cmd.exe 中获得 %Ix=y% ... :)【参考方案4】:我最喜欢的:
sudo !!
使用 sudo 重新运行上一个命令。
【讨论】:
这是***.com/questions/211378/hidden-features-of-bash/…的特例 这几乎就像在说做它!【参考方案5】:更多魔法组合键:
Ctrl + r 在您的命令历史记录中开始“反向增量搜索”。当您继续键入时,它会检索包含您输入的所有文本的最新命令。
Tab 补全您目前输入的单词,如果它没有歧义的话。
Tab Tab 列出您目前输入的单词的所有补全。
Alt + * inserts 所有可能的补全,这特别有用,例如,如果您刚刚输入了具有潜在破坏性的命令通配符:
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 + els -N --color=tty -T 0 /home/cramey
【讨论】:
+1 表示 alt+*(或 alt-shift-8),让您看到即将犯的错误 我打开了 show-all-if-ambiguous 以防止两次点击 Tab。【参考方案6】:取回历史命令和参数
可以使用!
运算符选择性地访问以前的命令和参数。当您处理长路径时,它非常有用。
您可以使用history
检查您的最后命令。
您可以使用以前的命令,!<n>
是 n
中的命令在 history
中的索引,负数从历史上的最后一个命令开始倒数。
ls -l foo bar
touch foo bar
!-2
!:<n>
可以使用之前的参数,0 是命令,>= 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
【讨论】:
^R 键盘快捷键也很方便 我也喜欢 alt-^(美国键盘上的 alt-shift-6)。它扩展了 !:2 之类的历史序列,因此您可以在运行命令之前查看命令将要执行的操作。 而不是$!尝试输入 ESC+。最后一个参数将出现在您的光标下方。【参考方案7】:我喜欢 -x 功能,它允许查看脚本中发生了什么。
bash -x script.sh
【讨论】:
【参考方案8】:SECONDS=0; sleep 5 ; echo "that took approximately $SECONDS seconds"
秒
每次这个参数 引用,秒数 因为返回了 shell 调用。 如果给 SECONDS 赋值, 随后返回的值 参考是秒数 因为赋值加上值 分配的。如果 SECONDS 未设置,则 失去了它的特殊属性,即使 它随后被重置。
【讨论】:
【参考方案9】:这是我的最爱之一。这将选项卡完成设置为不区分大小写。它非常适合快速输入目录路径,尤其是在文件系统默认不区分大小写的 Mac 上。我把它放在我的主文件夹中的.inputrc
中。
set completion-ignore-case on
【讨论】:
我不知道这个,谢谢。这在我的 ~/.inputrc 中已经被注释掉了。我打开了它并显示所有如果不明确。【参考方案10】:特殊变量random:
if [[ $(($RANDOM % 6)) = 0 ]]
then echo "BANG"
else
echo "Try again"
fi
【讨论】:
# [ $[ $RANDOM % 6 ] == 0 ] && rm -rf / ||回声“你活着”:) 算术评估中不需要$
sigil;无需单独评估和测试:if (( RANDOM % 6 == 0 )); then echo "BANG"; else echo "Try again"; fi
甚至更短:(( RANDOM % 6 )) && echo "Try again" || echo "BANG"
。【参考方案11】:
正则表达式处理
最近 bash 发布的功能正则表达式匹配,所以你可以这样做:
if [[ "mystring" =~ REGEX ]] ; then
echo match
fi
其中 REGEX 是格式由 man re_format 描述的原始正则表达式。
任何括号部分的匹配都存储在 BASH_REMATCH 数组中,从元素 1 开始(元素 0 是整个匹配的字符串),因此您也可以使用它来进行正则表达式驱动的解析。
【讨论】:
不用将正则表达式括在引号中感觉有点奇怪。 . .【参考方案12】:Ctrlx Ctrle
这会将当前命令加载到变量 VISUAL 中定义的编辑器中。这对于此处列出的一些长命令非常有用。
使用 vi 作为编辑器:
export VISUAL=vi
【讨论】:
set -o vi
然后 Esc 命令进入内联编辑,简单的“v”将命令拉入完整的 vi 编辑器。【参考方案13】:
快速和肮脏的错别字更正(特别适用于慢速连接上的长命令,因为使用命令历史并滚动浏览它会很糟糕):
$ cat /proc/cupinfo
cat: /proc/cupinfo: No such file or directory
$ ^cup^cpu
还可以尝试!:s/old/new
,它在上一个命令中将旧的替换为新的一次。
如果您想替换多次出现,您可以使用!:gs/old/new
进行全局替换。
您可以将gs
和s
命令用于任何历史事件,例如
!-2:s/old/new
在倒数第二个命令中将old
替换为new
(一次)。
【讨论】:
有没有办法找到更多关于这个或类似功能的信息?用谷歌搜索 ^foo^bar 并不是那么令人满意:)man bash
中的事件指示符和修饰符。尝试!:s/old/new
将旧命令替换为新命令一次。如果要替换多次出现,可以使用!:gs/old/new
进行全局替换。这可以与 James 的帖子 (***.com/questions/211378/hidden-features-of-bash/…) 结合使用,例如:!$:s/old/new
(在上一个命令的最后一个参数中用 new 代替 old),!-2:0:gs/a/s !-2*
(在倒数第二个命令名称中用 s 代替每次出现的 a并添加倒数第二个命令的所有参数)。祝你好运!【参考方案14】:
这是我最喜欢的两个:
要检查没有真正执行脚本的语法,请使用:
bash -n script.sh
返回上一个目录(是的,我知道 pushd 和 popd,但这样更快)
cd -
【讨论】:
"cd -" 如果您忘记将目录推送到堆栈但仍想返回那里,则具有工作的优势。【参考方案15】:使用中缀布尔运算符
考虑简单的 if:
if [ 2 -lt 3 ]
then echo "Numbers are still good!"
fi
那个 -lt 看起来有点丑。不是很现代。如果您在布尔表达式周围使用双括号,则可以使用普通的布尔运算符!
if [[ 2 < 3 ]]
then echo "Numbers are still good!"
fi
【讨论】:
这不是 Bash 的一个特性,而是一个外部程序:是的,'[[' 是一个独立的程序。 madmath:我想你会发现 [ 通常是要测试的符号链接或硬链接,而 [[ 是内置的 shell。它需要由 shell 解析,否则 不,'[' 是一个独立的程序。 '[[' 不是 $ type [[ [[ 是一个shell关键字 $ which [[ $ # 无输出 显然 SO 不喜欢 cmets 中的换行符,希望这不会太难解析。那是在带有 Bash 3.2.39 的 Ubuntu 上,顺便说一句。【参考方案16】:数组:
#!/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
可以在Advanced Bash-Scripting Guide 中找到有关数组(和其他高级 bash 脚本内容)的更多详细信息。
【讨论】:
【参考方案17】:在显示 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,然后坐下来观察混乱的发展。
【讨论】:
【参考方案18】:来自 bash man
页面的魔法组合键:
Ctrl + a 和 Ctrl + e 将光标移动到分别是当前行。
Ctrl + t 和 Alt + t 用当前的,然后将光标向前移动。
Alt + u 和 Alt + l 转换当前单词(从光标到结尾)大写和小写。
提示:按 Alt + – 后跟这些命令中的任何一个来转换当前的 开始单词。
奖金man
提示:
查看man
页面时,使用/ 在页面中搜索文本。使用 n 跳转到下一场比赛或使用 N 跳转到上一场比赛。
利用其格式,加快您在 man
页面中搜索特定命令或子部分的速度:
o 不要键入 /history expansion 来查找该部分,而是尝试 /^history,使用插入符号 (^
) 仅查找 以“历史”开头。
o 尝试使用 / read 并在前面加上几个空格,以搜索该内置命令。内置函数始终在 man
页面中缩进。
【讨论】:
【参考方案19】:export TMOUT=$((15*60))
在 15 分钟空闲时间后终止 bash,设置为 0 以禁用。我通常把它放在我的根帐户上的 ~/.bashrc 中。它在管理您的盒子时很方便,您可能会在离开终端之前忘记注销。
【讨论】:
【参考方案20】:撤消
C-S-- Control Shift Minus 撤消键入操作。
杀死/猛击
任何删除操作Cw(删除前一个单词),Ck(删除到行尾),Cu(删除到行首) 等... 将已删除的文本复制到终止环,您可以使用以下命令粘贴最后一个终止:Cy 并使用 Alt-y 循环(并粘贴)已删除项目的环
【讨论】:
【参考方案21】:通过设置FIGNORE
变量,您可以在制表符完成时忽略某些文件。
例如,如果您有一个 subverion 存储库,并且想要更轻松地导航,则可以这样做
export FIGNORE=".svn"
现在您可以cd
而不会被.svn
目录阻止。
【讨论】:
【参考方案22】:使用算术:
if [[ $((2+1)) = $((1+2)) ]]
then echo "still ok"
fi
【讨论】:
令人惊讶的是有多少人不知道这一点,并在他们的脚本中使用 expr。 有时算术展开就足够了:((2 + 1 == 1 + 2))&&echo OK【参考方案23】:大括号扩展
使用 x,y,z 进行标准扩展:
$ echo foobar,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..f0..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
【讨论】:
【参考方案24】:我最近阅读了Csh Programming Considered Harmful,其中包含这个惊人的宝石:
考虑管道:
A | B | C
你想知道 C 的状态,嗯,很简单:它在 $? 中,或者 csh 中的 $ 状态。但是如果你想从 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;
【讨论】:
你想要的是使用 PIPESTATUS 变量,它是管道中每个命令的退出状态的数组。 $PIPESTATUS[0] 就是你想要的。 史蒂夫,我从来不知道 - 在这里发布它作为答案! (如果你愿意,我会支持它:)【参考方案25】:截断文件的内容(归零文件)
> file
具体来说,这对于截断日志文件非常有用,当文件被另一个进程打开时,仍然可能写入文件。
【讨论】:
为了防止您意外截断文件,set -o noclobber
。然后你需要使用>| file
来截断一个文件。【参考方案26】:
不是一个真正的功能,而是一个方向:我在commandlinefu.com 发现了许多“隐藏功能”、秘密和各种 bash 实用性。这个答案的许多评价最高的答案,我在那个网站上学到的:)
【讨论】:
【参考方案27】:另一个小的: Alt+#
退出当前行并将其移入历史缓冲区。
因此,当您组装命令行时,您需要发出临时命令,例如找到一个文件,你只需按 alt+#,发出另一个命令,进入历史记录,取消注释并继续。
【讨论】:
【参考方案28】:用大括号代替 for 循环中的 do
和 done
For
循环体通常在do...done
(只是一个例子):
for f in *;
do
ls "$f";
done
但我们可以使用大括号来使用 C 风格:
for f in *;
ls "$f";
我认为这看起来比do...done
更好,我更喜欢这个。我还没有在任何 Bash 文档中找到它,所以这确实是一个隐藏功能。
【讨论】:
【参考方案29】: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 ""
【讨论】:
【参考方案30】:这些属性是我最喜欢的另一个。
export HISTCONTROL=erasedups
export HISTSIZE=1000
第一个确保 bash 不会多次记录命令,这将真正提高 history
的实用性。另一个将历史记录大小从默认的 100 扩展到 1000。我实际上在我的机器上将它设置为 10000。
【讨论】:
以上是关于Bash 的隐藏功能的主要内容,如果未能解决你的问题,请参考以下文章