Bash, Zsh and commonly used Shell commands

Bash的使用

显示 “Hello world!”

echo Hello world!

每一句指令以换行或分号隔开

echo ‘This is the first line’; echo ‘This is the second line’

声明一个变量

Variable=“Some string”

这是错误的做法: Variable = “Some string”

原因: Bash 会把 Variable 当做一个指令,由于找不到该指令,因此这里会报错。

也不可以这样: Variable= ‘Some string’

原因: Bash 会认为 ‘Some string’ 是一条指令,由于找不到该指令,这里再次报错。这个例子中 ‘Variable=’ 这部分会被当作仅对 ‘Some string’ 起作用的赋值。)

使用变量

1
2
3
echo $Variable
echo "$Variable"
echo '$Variable'

当你赋值 (assign) 、导出 (export),或者以其他方式使用变量时,变量名前不加 $。如果要使用变量的值, 则要加$

注意: ' (单引号) 不会展开变量(即会屏蔽掉变量)。

在变量内部进行字符串代换

echo ${Variable/Some/A}

会把 Variable 中首次出现的 “some” 替换成 “A”。

变量的截取

Length=7

echo ${Variable:0:Length}

这样会仅返回变量值的前7个字符

变量的默认值

echo ${Foo:-"DefaultValueIfFooIsMissingOrEmpty"}

对 null (Foo=) 和空串 (Foo="") 起作用; 零(Foo=0)时返回0

注意这仅返回默认值而不是改变变量的值

内置变量

下面的内置变量很有用

1
2
3
4
5
echo "Last program return value: $?"
echo "Script's PID: $$"
echo "Number of arguments: $#"
echo "Scripts arguments: $@"
echo "Scripts arguments separated in different variables: $1 $2..."

读取输入

1
2
3
echo "What's your name?"
read Name # 这里不需要声明新变量
echo Hello, $Name!

if 结构

’man test’ 可查看更多的信息

1
2
3
4
5
6
if [ $Name -ne $USER ]
then
echo "Your name isn't your username"
else
echo "Your name is your username"
fi

根据上一个指令执行结果决定是否执行下一个指令

1
2
echo "Always executed" || echo "Only executed if first command fails"
echo "Always executed" && echo "Only executed if first command does NOT fail"

在 if 语句中使用 && 和 || 需要多对方括号

1
2
3
4
5
6
7
8
9
if [ $Name == "Steve" ] && [ $Age -eq 15 ]
then
echo "This will run if $Name is Steve AND $Age is 15."
fi

if [ $Name == "Daniya" ] || [ $Name == "Zach" ]
then
echo "This will run if $Name is Daniya OR Zach."
fi

表达式的格式

echo $(( 10 + 5 ))

指令可以带有选项

与其他编程语言不同的是,bash 运行时依赖上下文。比如,使用 ls 时,列出当前目录。

ls -l 列出文件和目录的详细信息

前一个指令的输出可以当作后一个指令的输入

grep 用来匹配字符串。

列出当前目录下所有的 txt 文件

ls -l | grep "\.txt"

^EOF$ 作为结束标记从标准输入读取数据并覆盖 hello.py

1
2
3
4
5
6
7
8
9
cat > hello.py << EOF
#!/usr/bin/env python
from __future__ import print_function
import sys
print("#stdout", file=sys.stdout)
print("#stderr", file=sys.stderr)
for line in sys.stdin:
print(line, file=sys.stdout)
EOF

重定向可以到输出,输入和错误输出

1
2
3
4
5
6
7
python hello.py < "input.in"
python hello.py > "output.out"
python hello.py 2> "error.err"
python hello.py > "output-and-error.log" 2>&1
python hello.py > /dev/null 2>&1
# > 会覆盖已存在的文件, >> 会以累加的方式输出文件中。
python hello.py >> "output.out" 2>> "error.err"

覆盖 output.out, 追加 error.err 并统计行数

1
2
info bash 'Basic Shell Features' 'Redirections' > output.out 2>> error.err
wc -l output.out error.err

运行指令并打印文件描述符 (比如 /dev/fd/123)

1
2
# 具体可查看: man fd
echo <(echo "#helloworld")

以 “#helloworld” 覆盖 output.out

1
2
3
4
cat > output.out <(echo "#helloworld")
echo "#helloworld" > output.out
echo "#helloworld" | cat > output.out
echo "#helloworld" | tee output.out >/dev/null

清理临时文件并显示详情(增加 ‘-i’ 选项启用交互模式)

1
rm -v output.out error.err output-and-error.log

一个指令可用$( )嵌套在另一个指令内部

以下的指令会打印当前目录下的目录和文件总数

1
echo "There are $(ls | wc -l) items here."

反引号起相同作用,但不允许嵌套

优先使用 $()

1
echo "There are `ls | wc -l` items here."

Bash 的 case 语句与 Java 和 C++ 中的 switch 语句类似

1
2
3
4
5
6
case "$Variable" in
# 列出需要匹配的字符串
0) echo "There is a zero.";;
1) echo "There is a one.";;
*) echo "It is not null.";;
esac

循环遍历给定的参数序列

变量$Variable的值会被打印 3 次

1
2
3
4
for Variable in {1..3}
do
echo "$Variable"
done

传统的 “for循环”

1
2
3
4
for ((a=1; a <= 3; a++))
do
echo $a
done

也可以用于文件

用 cat 输出 file1 和 file2 内容

1
2
3
4
for Variable in file1 file2
do
cat "$Variable"
done

或作用于其他命令的输出

对 ls 输出的文件执行 cat 指令

1
2
3
4
for Output in $(ls)
do
cat "$Output"
done

while 循环

1
2
3
4
5
while [ true ]
do
echo "loop body here..."
break
done

使用函数

定义函数

1
2
3
4
5
6
7
function foo ()
{
echo "Arguments work just like script arguments: $@"
echo "And: $1 $2..."
echo "This is a function"
return 0
}

更简单的方法

1
2
3
4
5
bar ()
{
echo "Another way to declare functions!"
return 0
}

调用函数

1
foo "My name is" $Name

有很多有用的指令需要学习

打印 file.txt 的最后 10 行

1
tail -n 10 file.txt

打印 file.txt 的前 10 行

1
head -n 10 file.txt

将 file.txt 按行排序

1
sort file.txt

报告或忽略重复的行,用选项 -d 打印重复的行

1
uniq -d file.txt

打印每行中 ‘,’ 之前内容

1
cut -d ',' -f 1 file.txt

将 file.txt 文件所有 ‘okay’ 替换为 ‘great’(兼容正则表达式)

1
sed -i 's/okay/great/g' file.txt

将 file.txt 中匹配正则的行打印到标准输出

这里打印以 “foo” 开头, “bar” 结尾的行

"^foo.*bar$" file.txt```
1
2
3
4

使用选项 "-c" 统计行数

```grep -c "^foo.*bar$" file.txt

如果只是要按字面形式搜索字符串而不是按正则表达式,使用 fgrep (或 grep -F)

1
fgrep "^foo.*bar$" file.txt

以 bash 内建的 ‘help’ 指令阅读 Bash 自带文档

1
2
3
4
5
6
help
help help
help for
help return
help source
help .

用 man 指令阅读相关的 Bash 手册

1
2
3
apropos bash
man 1 bash
man bash

用 info 指令查阅命令的 info 文档 (info 中按 ? 显示帮助信息)

1
2
3
4
apropos info | grep '^info.*('
man info
info info
info 5 info

阅读 Bash 的 info 文档

1
2
3
4
info bash
info bash 'Bash Features'
info bash 6
info --apropos bash

Zsh的配置与使用

不少程序员都觉得Mac的一大优势就是其Shell,也有很多人觉得Mac与Linux在Shell上很相似。不错,但是Mac还是略胜一筹或者说高一个量级。今天,我将向大家介绍一个Mac特有的Shell(Linux也可以安装,但是不是系统自带。)—— Zsh。

切换到Zsh

使用cat /etc/shells指令,我们可以看看自己的系统有哪些Shells,下面是我的Mac的结果:

1
2
3
4
5
6
7
/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/usr/local/bin/fish

使用这个指令切换到Zsh:chsh -s /bin/zsh。(想使用其他Shell也是同样的指令哦。)

这是,我们的Shell配置文件就为.zshrc了。

我觉得从这里我们应该可以知道,为什么之前的Shell配置文件要以.bash_profile命名了吧。因为Mac默认Shell是Bash。

迁移Bash配置

我使用Bash有好几年了,那些配置都是一些环境变量啊什么的,如果在Zsh的配置里再写一遍,无疑是一件很费时又低效的事。那有没有什么快捷的方式呢?当然有!

通过如下指令:source ~/.bash_profile就可以将.bash_profile里的配置全部引入到.zshrc中了。同理,如果你想自己写配置,也可以通过这种方式引入。(后文你将看到一个第三方工具就是这么做的。)

安装oh my zsh

通过wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | sh指令安装。

这时我们发现在.zshrc文件中,多了两行:

1
2
export ZSH=/Users/NAME/.oh-my-zsh
source $ZSH/oh-my-zsh.sh

自定义Shell主题

使用oh my zsh主要的原因是使用其提供的漂亮的主题,主题目录在.oh-my-zsh/themes/下,选择主题ZSH_THEME="robbyrussell"。这时我的Shell主题就是robbyrussell了。

打开robbyrussell.zsh-theme文件,我们可以看见几条配置。

我将其中的PROMPT修改为:

PROMPT='${ret_status} %{$fg[cyan]%}%d %{$reset_color%} $(git_prompt_info)%{$fg_bold[red]%}>%{$fg_bold[yellow]%}>%{$fg_bold[green]%}> '

这时我的Shell就变成了这样:

Zsh

可以发现我的定制有:显示绝对路径,>>>等。

还有很多主题与配置,大家可以自己尝试。

定制Shell

Zsh还有个功能就是“别名”。不知道大家有没有这样的经历,需要打开.plist这样的文件,如果用普通编辑器打开会非常界面不友好,而用Xcode打开则完美可观。那怎么在控制台直接用Xcode打开文件呢?(其他软件同理)

我在.zshrc中添加:alias xcode="/Applications/Xcode.app/Contents/MacOS/Xcode",之后我就可以使用xcode X来用Xcode打开X文件了。

我们也可以为某种类型文件设置默认打开方式:alias -s html=atom(当我们键入.html文件时,会自动用Atom打开)。

安装插件

oh my zsh为Zsh提供了100+插件,如果我们需要安装某插件,只需要在.zshrc文件中的plugins=()中添加,用空格隔开,只需要填插件名字,默认添加了git

在这里我向大家介绍几种网上很常见的插件:

  1. git当你处于一个 git 受控的目录下时,Shell 会明确显示 「git」和 branch,如上图所示,另外对 git 很多命令进行了简化,例如 gco=’git checkout’、gd=’git diff’、gst=’git status’、g=’git’等等,熟练使用可以大大减少 git 的命令长度,命令内容可以参考~/.oh-my-zsh/plugins/git/git.plugin.zsh。
  2. osxtab 增强,quick-look filename 可以直接预览文件,man-preview grep 可以生成 grep手册 的pdf 版本等。
  3. autojump像他的名字一样,提供自动补全等很多功能,大家自己去尝试吧。

注意:安装autojump建议使用Homebrew

brew install autojump

然后按照提示将一句类似这个

[ -f /usr/local/etc/profile.d/autojump.sh ] && . /usr/local/etc/profile.d/autojump.sh

的句子插入到.zshrc文件中即可。

其他Shell常用指令

统计文件夹中文件数量

当前文件夹下文件个数[不包括文件夹]

$ ls -l |grep "^-"|wc -l

当前目录下文件夹个数

$ ls -lR | grep "^d" | wc -l

当前文件夹下文件数目[包括子目录]

$ ls -lR| grep "^-" | wc -l

登录服务器

$ ssh [-p 端口] username@host_address #Enter后输入密码

conda虚拟环境

新建环境

$ conda create -n 环境名 python=X.X #X.X = 2.7、3.6等

激活环境

$ source activate 环境名

环境中安装额外的包

$ conda install -n 环境名 packages

删除环境中的某个包

$ conda remove --name 环境名  package

关闭虚拟环境

$ source deactivate

删除环境

$ conda remove -n 环境名 --all

文件链接

$ ln -s 源 目的

查寻文件或命令的路径

文件中字符串的查寻

$ grep string file

显示命令的路径

$ whereis command

显示命令的路径,及使用者所定义的别名

$ which command

显示命令功能的摘要

$ whatis command

搜寻指定路径下某文件的路径

$ find path -name filename -print

查看进程并关闭

1
2
3
4
$ ps [-aux] 
# -x自己的,
# -au所有用户的,
# -aux系统内部和所有用户的

$ kill [-9] PID(进程号)

查看后台运行的进程

$ jobs

$ kill %n #n为jobs查询出的后台作业号

命令记录表

设定命令记录表长度

$ set history = 长度

查看命令记录表的内容

$ history

重复执行前一个命令

$ !!

重复执行命令记录表命令编号n的命令

$ !n

重复前面执行过的以’xxx’为起始字符串的命令

$ !xxx



The link of this page is http://home.meng.uno/articles/61f3f0dd/ . Welcome to reproduce it!

© 2018.02.08 - 2021.06.19 Mengmeng Kuang  保留所有权利!

:D 获取中...

Creative Commons License