您最喜欢的使用 Bash 的命令行技巧是什么?[关闭]
-
09-06-2019 - |
题
我们都知道如何使用 <ctrl>-R
通过历史反向搜索,但你知道你可以使用 <ctrl>-S
如果您设置,则转发搜索 stty stop ""
?另外,您是否尝试过运行 bind -p 来查看列出的所有键盘快捷键?Mac OS X 上默认有超过 455 个。
您最喜欢的晦涩难懂的技巧、键盘快捷键或使用 bash 的 shopt 配置是什么?
解决方案 7
运行命令时,有时我想使用前面的参数运行命令。为此,您可以使用以下快捷方式:
$ mkdir /tmp/new
$ cd !!:*
有时,如果我需要在文件列表上运行一堆命令,我会打破单行循环来代替使用 find。
for file in *.wav; do lame "$file" "$(basename "$file" .wav).mp3" ; done;
在我的 .bash_login (或 .bashrc)中配置命令行历史选项非常有用。以下是我在 Macbook Pro 上使用的一系列设置。
设置以下内容可以使 bash 删除历史记录中的重复命令:
export HISTCONTROL="erasedups:ignoreboth"
我也把我的历史记录调得很高。为什么不?它似乎并没有减慢当今微处理器的速度。
export HISTFILESIZE=500000
export HISTSIZE=100000
我做的另一件事是忽略我的历史记录中的一些命令。无需记住退出命令。
export HISTIGNORE="&:[ ]*:exit"
你肯定想设置 histappend。否则,退出时 bash 会覆盖您的历史记录。
shopt -s histappend
我使用的另一个选项是cmdhist。这使您可以将多行命令作为一条命令保存到历史记录中。
shopt -s cmdhist
最后,在 Mac OS X 上(如果您不使用 vi 模式),您需要将 <CTRL>-S 重置为滚动停止。这会阻止 bash 将其解释为正向搜索。
stty stop ""
其他提示
快速重命名/移动带有后缀的文件:
cp /home/foo/realllylongname.cpp{,-old}
这扩展到:
cp /home/foo/realllylongname.cpp /home/foo/realllylongname.cpp-old
cd -
它是相当于后退按钮的命令行(将您带到您所在的上一个目录)。
另一个最喜欢的:
!!
重复您的上一个命令。最有用的形式:
sudo !!
我最喜欢的是“^string^string2”,它接受最后一个命令,用 string2 替换 string 并执行它
$ ehco foo bar baz
bash: ehco: command not found
$ ^ehco^echo
foo bar baz
改名
例子:
$ ls
this_has_text_to_find_1.txt
this_has_text_to_find_2.txt
this_has_text_to_find_3.txt
this_has_text_to_find_4.txt
$ rename 's/text_to_find/been_renamed/' *.txt
$ ls
this_has_been_renamed_1.txt
this_has_been_renamed_2.txt
this_has_been_renamed_3.txt
this_has_been_renamed_4.txt
太有用了
我是 的粉丝 !$
, !^
和 !*
Expandos,从最近提交的命令行返回:最后一个项目、第一个非命令项目以及所有非命令项目。即(请注意,shell 首先打印出命令):
$ echo foo bar baz
foo bar baz
$ echo bang-dollar: !$ bang-hat: !^ bang-star: !*
echo bang-dollar: baz bang-hat: foo bang-star: foo bar baz
bang-dollar: baz bang-hat: foo bang-star: foo bar baz
当你说时,这会派上用场 ls filea fileb
, ,并想要编辑其中之一: vi !$
或两者都: vimdiff !*
. 。也可以概括为“ n
第一个参数”就像这样:
$ echo foo bar baz
$ echo !:2
echo bar
bar
最后,使用路径名,您可以通过附加来获取路径的一部分 :h
和 :t
到上述任何一个扩展:
$ ls /usr/bin/id
/usr/bin/id
$ echo Head: !$:h Tail: !$:t
echo Head: /usr/bin Tail: id
Head: /usr/bin Tail: id
如何列出 仅有的 当前目录中的子目录 ?
ls -d */
这是一个简单的技巧,但你不会知道我需要多少时间才能找到它!
ESC键.
插入最后一个 bash 命令的最后一个参数。它比你想象的更方便。
cp file /to/some/long/path
光盘 ESC键.
你当然可以 ”diff file1.txt file2.txt
",但 Bash 支持 流程替代, ,这使您可以 diff
命令的输出。
例如,假设我想确保我的脚本提供我期望的输出。我可以将我的脚本包装在 <( ) 中并将其提供给 diff
获得快速而肮脏的单元测试:
$ cat myscript.sh
#!/bin/sh
echo -e "one\nthree"
$
$ ./myscript.sh
one
three
$
$ cat expected_output.txt
one
two
three
$
$ diff <(./myscript.sh) expected_output.txt
1a2
> two
$
再举一个例子,假设我想检查两台服务器是否安装了相同的 RPM 列表。不是通过 ssh 连接到每个服务器,而是将每个 RPM 列表写入单独的文件,然后执行 diff
在这些文件上,我可以这样做 diff
从我的工作站:
$ diff <(ssh server1 'rpm -qa | sort') <(ssh server2 'rpm -qa | sort')
241c240
< kernel-2.6.18-92.1.6.el5
---
> kernel-2.6.18-92.el5
317d315
< libsmi-0.4.5-2.el5
727,728d724
< wireshark-0.99.7-1.el5
< wireshark-gnome-0.99.7-1.el5
$
在高级弹拨手指南中还有更多示例 http://tldp.org/LDP/abs/html/process-sub.html.
我最喜欢的命令是“ls -thor”
它召唤出 众神的力量 以方便可读的格式列出最近修改的文件。
更多的是新奇,但它很聪明......
最常用的 10 个命令:
$ history | awk '{print $2}' | awk 'BEGIN {FS="|"}{print $1}' | sort | uniq -c | sort -nr | head
示例输出:
242 git
83 rake
43 cd
33 ss
24 ls
15 rsg
11 cap
10 dig
9 ping
3 vi
^R反向搜索。按 ^R,键入要匹配的上一个命令的片段,然后按 ^R 直到找到所需的命令。这样我就不必记住仍然在我的历史记录中的最近使用的命令。不仅是 bash,还包括:^E 表示行尾,^A 表示行首,^U 和 ^K 分别删除光标之前和之后的内容。
我经常使用 vi、ls 等别名。但有时你想转义别名。只需在前面的命令中添加一个反斜杠即可:
例如:
$ alias vi=vim
$ # To escape the alias for vi:
$ \vi # This doesn't open VIM
很酷,不是吗?
以下是一些配置调整:
~/.inputrc
:
"\C-[[A": history-search-backward
"\C-[[B": history-search-forward
这与以下操作相同 ^R
但改用箭头键。这意味着我可以输入(例如) cd /media/
然后按向上箭头转到我的最后一件事 cd
到里面 /media/
文件夹。
(我使用 Gnome 终端,您可能需要更改其他终端模拟器的转义码。)
Bash 补全也非常有用,但它是一个更微妙的补充。在 ~/.bashrc
:
if [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
这将启用每个程序的制表符完成功能(例如当命令行以以下字符开头时尝试制表符补全 evince
只会显示 evince 可以打开的文件,并且还会使用制表符完成命令行选项)。
也可以很好地与此配合使用 ~/.inputrc
:
set completion-ignore-case on
set show-all-if-ambiguous on
set show-all-if-unmodified on
我经常使用以下内容:
这 :p
修改器打印历史结果。例如。
!!:p
将打印最后一个命令,以便您可以在再次运行之前检查它是否正确。只需输入 !!
来执行它。
与此相类似:
!?foo?:p
将在您的历史记录中搜索包含字符串“foo”的最新命令并打印它。
如果不需要打印的话
!?foo
进行搜索并立即执行。
我有一个秘密武器: 贝壳福。
有数千个聪明的技巧、酷炫的技巧和高效的食谱,大多数时候都可以在一行中找到。
我喜欢的一个(但我有点作弊,因为我现在大多数 Unix 系统上都安装了 Python):
alias webshare='python -m SimpleHTTPServer'
现在,每次您键入“webshare”时,都可以通过端口 8000 访问当前目录。当您想与本地网络上的朋友共享文件而无需 USB 密钥或远程目录时,这真的很好。流媒体视频和音乐也可以。
当然还有经典的叉子炸弹,它完全没用,但仍然很有趣:
$ :(){ :|:& };:
不要在生产服务器中尝试这样做......
您可以将 watch 命令与另一个命令结合使用来查找更改。一个例子是,当我测试路由器时,我想获得信噪比等方面的最新数据。
watch --interval=10 lynx -dump http://dslrouter/stats.html
type -a PROG
为了找到所有可用的prog的地方,通常在〜/bin的某个地方,而不是预期的/usr/bin/preg中的一个。
我喜欢用以下方式构建命令 回声 并将它们通过管道传输到 shell:
$ find dir -name \*~ | xargs echo rm
...
$ find dir -name \*~ | xargs echo rm | ksh -s
为什么?因为它可以让我在做之前先看看要做什么。这样,如果我遇到可怕的错误(例如删除我的主目录),我可以在它发生之前捕获它。显然,这对于破坏性或不可撤销的行为最为重要。
下载大文件时我经常这样做:
while ls -la <filename>; do sleep 5; done
然后当我完成后只需按 ctrl+c (或者如果 ls
返回非零)。它类似于 watch
程序,但它使用 shell,因此它可以在没有 watch
.
另一个有用的工具是 netcat,或者 nc
. 。如果你这样做:
nc -l -p 9100 > printjob.prn
然后,您可以在另一台计算机上设置打印机,但使用运行 netcat 的计算机的 IP 地址。当发送打印作业时,它被运行 netcat 的计算机接收并转储到 printjob.prn
.
pushd
和 popd
几乎总是派上用场
当我在树层次结构中广泛分散的位置使用多个目录时,一种首选的导航方式是使用 acf_func.sh(如下所列)。一旦定义,你可以做
光盘 -
查看最近的目录列表,带有数字菜单
光盘-2
转到第二个最近的目录。
使用非常方便,非常方便。
这是代码:
# do ". acd_func.sh"
# acd_func 1.0.5, 10-nov-2004
# petar marinov, http:/geocities.com/h2428, this is public domain
cd_func ()
{
local x2 the_new_dir adir index
local -i cnt
if [[ $1 == "--" ]]; then
dirs -v
return 0
fi
the_new_dir=$1
[[ -z $1 ]] && the_new_dir=$HOME
if [[ ${the_new_dir:0:1} == '-' ]]; then
#
# Extract dir N from dirs
index=${the_new_dir:1}
[[ -z $index ]] && index=1
adir=$(dirs +$index)
[[ -z $adir ]] && return 1
the_new_dir=$adir
fi
#
# '~' has to be substituted by ${HOME}
[[ ${the_new_dir:0:1} == '~' ]] && the_new_dir="${HOME}${the_new_dir:1}"
#
# Now change to the new dir and add to the top of the stack
pushd "${the_new_dir}" > /dev/null
[[ $? -ne 0 ]] && return 1
the_new_dir=$(pwd)
#
# Trim down everything beyond 11th entry
popd -n +11 2>/dev/null 1>/dev/null
#
# Remove any other occurence of this dir, skipping the top of the stack
for ((cnt=1; cnt <= 10; cnt++)); do
x2=$(dirs +${cnt} 2>/dev/null)
[[ $? -ne 0 ]] && return 0
[[ ${x2:0:1} == '~' ]] && x2="${HOME}${x2:1}"
if [[ "${x2}" == "${the_new_dir}" ]]; then
popd -n +$cnt 2>/dev/null 1>/dev/null
cnt=cnt-1
fi
done
return 0
}
alias cd=cd_func
if [[ $BASH_VERSION > "2.05a" ]]; then
# ctrl+w shows the menu
bind -x "\"\C-w\":cd_func -- ;"
fi
在按下可怕的回车键之前展开复杂的线条
- 替代+控制键+e — shell 扩展行 (可能需要使用 Esc键, 控制键+e 在你的键盘上)
- 控制键+_ — 撤消
- 控制键+X, * — 全局扩展字
$ echo !$ !-2^ *
替代+控制键+e
$ echo aword someotherword *
控制键+_
$ echo !$ !-2^ *
控制键+X, *
$ echo !$ !-2^ LOG Makefile bar.c foo.h
&C。
我一直偏向:
ctrl-E # move cursor to end of line
ctrl-A # move cursor to beginning of line
我也用 shopt -s cdable_vars
, ,然后您可以为公共目录创建 bash 变量。因此,对于我公司的源代码树,我创建了一堆变量,例如:
export Dcentmain="/var/localdata/p4ws/centaur/main/apps/core"
然后我可以通过更改到该目录 cd Dcentmain
.
pbcopy
这将复制到 Mac 系统剪贴板。您可以通过管道向它发送命令...尝试:
pwd | pbcopy
$ touch {1,2}.txt
$ ls [12].txt
1.txt 2.txt
$ rm !:1
rm [12].txt
$ history | tail -10
...
10007 touch {1,2}.txt
...
$ !10007
touch {1,2}.txt
$ for f in *.txt; do mv $f ${f/txt/doc}; done
从命令行使用“set -o vi”,或者更好的是在 .bashrc 中使用,可以使您在命令行上进入 vi 编辑模式。您从“插入”模式开始,这样您就可以像平常一样键入和退格,但如果您犯了“大”错误,您可以按 esc 键,然后使用“b”和“f”像在 vi 中一样移动。CW 改变一个词。在您调出要更改的历史命令后特别有用。
与上面的许多类似,我目前最喜欢的是按键 [alt]。(Alt 和“.”键一起)这与 $ 相同!(插入上一个命令的最后一个参数)除了它是立即的并且对我来说更容易键入。(只是不能在脚本中使用)
例如:
mkdir -p /tmp/test/blah/oops/something
cd [alt].
使用将多个命令串在一起 && 命令:
./run.sh && tail -f log.txt
或者
kill -9 1111 && ./start.sh