Bash基础(Mac端zsh环境)

166 阅读12分钟

常用bash命令

# 查看当前文件夹下所有文件&文件夹以及其权限
ls -l

:<<EOF
# 以下分别是文件夹和文件的结果
drwxr-xr-x@ 31 eric  staff     992  4 18  2024 code-pre
-rwxr-xr-x@  1 eric  staff     933 12 27 01:13 test.sh
第一个字符:表示文件类型:
    d(表示目录/文件夹)【常见】
    -(表示文件)【常见】
    b(块文件,比如磁盘,光驱,软盘)【不常见,了解】
    c(字符文件,比如系统设备文件:/dev/null)【不常见,了解】
    p(管道文件)【不常见,了解】
接下来的每三个一组分别是Owner(所有者)、Group(所属组)、others(其他用户)的权限
  r(4):代表读(read)权限
  w(2):代表写(write)权限
  x(1):代表执行(execute)权限
接下来的数字:代表硬连接数,即有多少个硬链接指向这个文件或目录
普通文件一般是1,目录至少是2,因为除自身(.)还有上级目录(..)也是指向该目录的硬链接
eric:是文件或目录的所有者
staff:所属组
接下来的数字是文件或目录大小(字节数)
接下来是月,日,时分
EOF

# 添加权限
chmod +x file
chmod 1 file # 通过数字给文件加执行权限
chmod 755 file # 所有者:(4+2+1)读写执行权限,所属组:(4+1)读和执行权限,其他用户:(4+1)读和执行读权限
chmod +rwx file


# 删除权限
chmod -r file
chmod -rwx file
chmod =r file # 只读
chmod =w file # 只写
chmod =rw file # 只读写
chmod =x file # 只有执行权限

# 针对不同用户设置权限
chmod u+x file # 给”所有者“加执行权限
chmod g+x file # 给”所属组“加执行权限
chmod o+x file # 给“其他用户”加执行权限

# 查看命令历史记录
history

# 查看命令历史记录文件路径
echo $HISTFILE

# 清空命令历史记录
history -c

# 调出命令历史记录中数第n条
!-n

# 调出命令历史记录中最后一条
!!
# 或
!$

# 从第N条开始查看命令历史记录
history n

# 设置别名(永久射中:~/.zshrc文件中添加alias h5='head -5')
alias h5='head -5'

# 删除别名
unalias h5

# 查看文件前N行
cat ./filePath | head -n


# bash配置文件
:<<EOF
~/.bash_profile
~/.zshrc
EOF

# 重定向与追加
:<<EOF
/dev/null:空设备文件,类似无限大的垃圾回收站(丢进去的东西无法恢复)
0:标准输入,路径:/dev/stdin
1:标准输出,路径:/dev/stdout
2:标准错误,路径:/dev/stderr
>:标准输出重定向,与1>相同
2>&1:把标准错误输出 重定向到 标准输出
&>file:标准输出 和 标准错误输出 都重定向到文件file中
>&file:标准输出 和 标准错误输出 都重定向到文件file中
EOF

# 以覆盖的方式将命令的标准输出重定向到file中
command 1> file
command > file # 默认是标准输出重定向,可以省略1

# 以覆盖的方式将命令的标准错误输出重定向到file中
command 2> file

# 以覆盖的方式将命令的标准输出和错误输出重定向到file中
command &> file
command &> /dev/null # 将标准输出和错误输出放到回收站,意思就是丢弃掉忽略掉

# 将命令的输出追加到file中
command >> file # 标准输出
command 2>> file # 错误输出
command $>> file # 标准正确和错误输出


# 输入重定向
command < file # 将file的内容作为command的输入
cat exam.sh # 预览文件

# 示例(将exam.sh输入到前面while命令,然后打印里面内容)
while read str 
do
 echo $str
done < exam.sh

# 将file的内容作为command的输入,并将command的处理结果输出到file2中
command file 

# wc命令:对文本进行统计,选项参数如下
:<<EOF
-c:统计字节数
-w:统计单词数
-l:统计行数
EOF
wc -l < exam.sh # 查看文件行数,用这个命令可以统计项目代码行数

# 在终端记录字节,单词,行数,输入内容后再次输入END+回车将展示统计结果
wc -l << END

:<<EOF
运行结果:
**Desktop** wc -l << END   
heredoc> 1
heredoc> 2
heredoc> 3
heredoc> END
       3
**Desktop**
EOF


# 管道| tee管道
# 1、管道|:管道,从一头进,另外一头出来,管道键一个程序/命令的标准输出作为另外一个程序的标准输入
man ls | less # man的标准输出作为less 的标准输入,以实现翻页的功能

# 2、tee管道:同时将程序的输出显示在屏幕上(或进入管道)和保存到文件中
cat /etc/password | tee exam.sh # 覆盖文件原有内容
cat /etc/password | tee -a exam.sh # 追加


# 命令排序
# && || ;
command1 && command2 # 只有1成功执行后才会执行2
ls / && echo "success" # 打印根目录,且输出success
ls dir && echo "success" # dir不存在,报错且不会输出success

command1 || command2 # 1没有成功执行时执行2
ls / || echo "success" # 打印根目录,但不输出success
ls dir || echo "success" # dir不存在,报错且输出success

# ;(分号)连接两个命令,不具备逻辑判断
cd /usr/local; echo "ignore" # 前面是否成功执行,ignore都会输出

通配符(和正则有一点不同)

字符含义实例
*匹配0个或多个任意字符a*b,a与b之间可以有任意长度的字符,也可以没有。例如:aabcb, ab, azxcb...
?匹配一个任意字符a2b,a与b之间必须但也只能存在一个字符,该字符可以是任意字符。例如:aab, abb, acb...
[list]匹配Iist中的任意单个字符a[xyz]b,a与b之间必须但也只能存在一个字符,该字符只能是x或y或2。例如:axb,ayb,azb
[!list]匹配除list中的任意单个字符a[!a-z]b,a与b之间必须但也只能存在一个字符,该字符不能是小写字母。例如:aAb,a0b...
[c1-c2]匹配c1-c2间的任意单个字符a[0-1]b,a与b之间必须但也只能存在个字符,该字符只能是数字。例如:a0b,a1b...
{string1,string2,...}匹配string1、string2等中的一个字符串a{abc,xyz,opq}b,a与b之间必须但也只能存在一个字符串,字符串只能是abc或xyz,opq,...。例如:aabcb, axyzb,aopqb,...

八、Shell脚本规范

### 1、风格规范
# 开头有“蛇棒”所谓shebang其实就是在很多脚本的第一行出现的以“#”开头的注释,他指明了当我们没有指定解释器的时候默认的解释器,一般可能是下面这样:

#!/bin/bash # 指定解释器

# 除了bash之外,可以用下面的命令查看本机支持的解释器
cat /etc/shells # 查看支持的解释器
:<<EOF
/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
EOF

echo $SHELL # 查看默认Shell解释器

:<<EOF
• 直接使用./a.sh来执行这个脚本的时候,如果没有shebang,就会默认使用$SHELL指定的解释器,否则就会用shebang指定的解释器
• 上面这种写法可能不太具备适应性,一般我们会用下面的方式来指定:#!/bin/bash/env bash1,这里不太懂先跳过
EOF

### 2、注释
:<<EOF
注释的意义不仅在于解释用途,而在于告诉我们注意事项,就像是一个 README。
具体的来说,对于Shell脚本,注释一般包括不面几个部分:
• shebang
• 脚本的参数
• 脚本的用途
• 脚本的注意事项
• 脚本的写作时间,作者,版权等
• 各个函数前的说明注释
• 一些校复杂的单行命令注释
EOF

### 3、参数要规范
:<<EOF
• 这一点很重要,当脚本需要接受参数的时候,一定要先判断参数是否合乎规范,并给出合适的回显,方便使用者了解参数的使用。
• 最少,最少,最少得判断下参数的个数
EOF
# 比如这样处理
if [[ $# != 2 ]]; then
  echo "parameter incorrect"
  exit 1
fi 

### 4、变量
:<<EOF
• 一般情况下会将一些重要的环境变量定义在开头,确保这些变量的存在。
• 这种定义方式有一个很常见的用途,最典型的应用就是,当本地安装了很多 java 版本时,可能需要指定一个java来用,这时就会在脚本开头重瓶定义JAVA_HOME以及PATH变量来进行控制。
• 一段好的代码通常是不会有很多硬编码在代码里的“魔数"的。如一定要有,通常是用一个变量的形式定义在开头,然后调用的时候直接调用这个变量,这样方便日后的修改。
EOF
# 比如:
source ~/.bash_profile
source $ZSH/oh-my-zsh.sh
export ANDROID_HOME=$HOME/Library/Android/sdk # ANDROID
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/platform-tools


### 5、缩进
:<<EOF
• 因为很多需要缩进的地方(比如if,for语包)都不长,很多人都懒得去缩进,而旦很多人不习惯用函数,导致缩进功能披弱化。
• 正确的缩进是很重要的,尤其是在写函数的时候,否则在阅读的时候很容易把函数体跟直接执行的命令搞混。
• 常见的缩进方法主要有"soft tab”和"hard tab'两种:
  • 所谓soft tab就是使用n个空格进行缩进(n通常是2或4)
  • 所谓hard tab当然就是指真实的"\t"字符
• 对于if和for语句之类的,最好不要把then,do这些关键字单独写一行,这样看上去比较丑。
EOF

### 6、命名有标准
:<<EOF
所谓命名规范,基本包含下面这几点:
• 文件名规范,以.sh结尾,方便识别
• 变量名字要有含义,不要拼错
• 统一命名风格,写Shell一般用小写字母加下划线
EOF

### 7、编码要统一
:<<EOF
在写脚本的时候尽量使用UTF-8编码,能够支持中文等一些奇奇怪怪的字符。不过虽然能写中文,但是在写注释以及打log的时候还是尽量英文,毕竟很多机器还是没有直接支持中文的,打出来可能会有乱码。
EOF

### 8、日志和回显
:<<EOF
• 日志的要性不必多说,能够方便回头纠错,在大型的项目里是非常重要的。
• 如果这个脚本是供用户直接在命令行使用的,那么最好还要能够在执行时实时回显执行过程,方便用户掌
控。
• 为了提高用户体验,会在回显中添加一些特效,比如颜色啊,闪烁啊之类的。
EOF

### 9、密码要移除
:<<EOF
• 不要把密码硬编写在脚本,尤其是当脚本托管在Github这类平台中时。
EOF

### 10、太长要分行
:<<EOF
• 在调用某些程序的时候,参数可能会很长,这时候为了保证较好的阅读体验,我们可以用反斜杠来分行,注意:放斜杠前有个空格
EOF
# 实例
echo "a \
b \
c \
"

### 11、代码要有效率
:<<EOF
• 在使用命令的时候要了解命令的具体做法,尤其当数据处理量大的时候,要时刻考虑该命令是否会影响效率
• 比如下面的两个sed命令:
sed -n '1p' file
sed -n '1p;1q' file

作用一样,都是获取文件的第一行.但是第一条命令会读取整个文件,而第二条命令只读取第一行。当文件很大的时候,仅仅是这样一条命令不一样就会造成巨大的效率差异。
当然,这里只是为了举一个例子,这个例子真正正确的用法应该是使用head-n file命令

勤用双引号
• 几乎所有的大佬都推荐在使用"$"来获取变量的时候最好加上双引。
• 不加上双引号在很多情况下都会造成很大的麻烦
EOF

### 12、学会查路径
:<<EOF
• 很多情况下,会先获取当前脚本的路径,然后以这个路径为基准,去找其他的路径。通常我们是直接用pwd以获得脚本的路径。
• 不过其实这样是不严谨的,pwd 获得的是当前Shell的执行路径,而不是当前脚本的执行路径。
• 正确的做法应该是下面这两种:
script_dir=$(cd $(dirname $0) && pwd)
script_dir=$(dirname $(readlink -f $0 ))

• 应当先cd进当前脚本的目录然后再pwd,或者直接读取当前脚本的所在路径。
EOF

### 13、代码要简短
:<<EOF
• 这里的简短不单单是指代码长度,而是指用到的命令数。原则上我们应当做到,能一条命令解决的问题绝不用两条命令解决。这不仅牵涉到代码的可读性,而且也关乎代码的执行效率。
• 最最经典的例子如下:
cat /etc/passwd grep root
grep root /etc/passwd

• cat命令最为人不齿的用法就是这样,用的没有任何意义,明明一条命令可以解決,非得加根管道
EOF


### 14、使用新写法
:<<EOF
这里的新写法不是指有多厉害,而是指可能更希望使用较新引入的一些语法,更多是偏向代码风格的.
• 尽量使用func(){}来定义函数,而不是func(){}
• 尽量使用[[]]来代替[]
• 尽量使用$()将命令的结果赋给变量,而不是反引号在复杂的场景下尽量使用# #printf代替echo进行回显
EOF


### 15、其他小技巧
:<<EOF
• 路径尽量保持绝对路径,不容易出错,如果非要用相对路径,最好用./修饰
• 优先使用bash的变量替换awk sed,这样更加简短
• 简单的if尽量使用 && ||,写成单行,比如:[[ $x > 2 ]] && echo $x
• 当export变量时,尽量加上子脚本的namespace,保证变量不冲中突【就是多加一下前缀】
• 会使用trap捕获信号,并在接受到终止信号时执行一些收尾工作
• 使用mktemp生成临时文件或文件夹
• 利用/dev/null过滤不友好的输出信息
• 会利用命令的返回值判断命令的执行情况
• 使用文件前要判断文件是否存在,否则做好异常处理
• 不要处理ls后的数据,比如:ls -l | awk '{print $8}'
• ls结果非常不确定,并且与平台有关
• 读取文件吋不要使用fot loop而要使用while read
EOF

shell脚本调试

# shell脚本的语法调试,使用bash的相关参数进行调试
sh [-nv] file.sh
:<<EOF
• -n:不要执行script,仅查询语法的问题
• -v:在执行script之前,先将script的内容输出到屏幕上
• -x:将使用的脚本的内容输出到屏幕吧,改参数经常被使用
EOF

# 检查语法问题
sh -n file.sh

# 执行器把脚本内容全打印出来
sh -v file.sh

# 打印执行过程的每一步,这样方便查看运行时变量的值等
sh -x file.sh

# 在脚本代码开头时设置设置调试
#!/bin/bash
set -xve # e:遇到错误终止执行脚本

脚本运行

# 1、工作目录执行
./file.sh

# sh bash执行
sh file.sh
bash file.sh

# 绝对路径执行
`pwd`/file.sh

# shell环境执行
. file.sh # Mac端报错
source file.sh

作业脱机管理

:<<EOF
1、将作业(进程)切换到后台可以避免由于误操作如:ctrl+c等导致的job被异常中断的情形,而脱机管理主要是针对终端异常断开的情形。
2、通常使用nohup命令来使得脱机或注销之后,Job依旧可以继续运行。也就是说nohup忽略所有挂断(SIGHUP)信号。
3、如果该方式命令之后未指定&符号,则job位于前台,指定&符号,则job位于后台。
EOF

# #下面是使用nohup的示例,可以省略自志的输出,因为原jo 的輪出会自动被nohup重定向到缺省的nohup.out日志文件
nohup exam.sh

# 查看进程的方式来查看脚本执行情况
ps -ef | grep ./exam.sh
# 501  1734  1429   0  5:00下午 ttys000    0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox --exclude-dir=.venv --exclude-dir=venv ./exam.sh

# 查看nohup.out文件
more nohup.out

# 日志文件也可以重定向,其中末尾&表示:将命令放到后台执行,这样当前的 Shell 可以继续接收其他命令,而不会因为 `exam.sh` 脚本的执行而被阻塞。
nohup exam.sh &> temp2.log &

# 常看当前运行的任务
jobs

screen命令使用

:<<EOF
一、简介
Screen 是一款由GNU计划开发的用于命令行终端切换的自由软件。用户可以通过该软件同时连接多个本地或远程的命令行会话,并在其间自由切换。GNU Screen可以看作是窗口管理器的命令行界面版本。它提供了统一的管理多个会话的界面和相应的功能。
1、会活恢复
• 只要Screen本易没有终止,在其内部运行的会话部可以恢复。这一点对于远程登录的用户特别有用,即使网络连接中断,用户也不会失去对已经打开的命令行会话的控制。只要再次登录到主机上执行screen-r就可以恢复会话的运行。同样在暂时离开的时候,也可以执行分离命令detach,在保证里面的程序正常运行的情况下让Screen挂起(切换到后台)。这一点和图形界面下的VNC很相似。
2、多窗口
• 在Screen环境下,所有的会话都独立的运行,并拥有各自的编号、输入、输出和窗口缓存。用户可以通过快捷键在不同的窗口下切换,并可以自由的重定向各个窗口的输入和输出。Screen实现了基本的文本操作,如复制粘贴等:还提供了类似滚动条的功能,可以直看窗口状况的历史记录。窗口还可以被分区和命名,还可以监视后台窗口的活动。会话共享Screen可以让一个或多个用户从不同终端多次登录一个会话,并共享会话的所有特性(比如可以看到完全相同的输出)。它同时提供了窗口访问权限的机制,可以对窗口进行密码保
3、安装screen
yum install screen
rpm -qa | grep screen # 查看安装好的命令

4、语法
screen [AmRvx -ls wipe][-d <作业名称>][-h <行数>][-r <作业名称>][-s][-S <作业名称>]

-A 将所有的视窗都调整为目前终端机的大小。
-d <作业名称> 将指定的screen作业离线。
-h <行数> 指定视窗的缓冲区行数。
-m 即使目前已在作业中的screen作业,仍强制建立新的scneen作业。
-r <作业名称>恢复窗线的screen作E业。
-R 先试图恢复离线的作业。若找不到离线的作业,即建立新的screen作业。
-s 指定建立新视窗时,所要执行的Shel1。
-S <作业名称> 指定screen作业的名称。
-v 显示版本信息。
-x 恢复之前离线的screen作业。
-ls或--list 显示目前所有的screen作业。
-wipe 检查目前所有的screen作业,并删除已经无法使用的screen作业。
EOF

# 常见用法
screen -S yourname # 新建一个叫younname的session
screen -ls # 列出当前所有的session
screen -r yourname # lyournamei session
screen -d yourname # 远程detach某个session
screen -d-r yourname # 结束当前session并回到younname这个session

# 创建会话(-m强制)
screen -dms session_name # session_name session名称

# 关闭会话
screen -X -S [session # you want to kill] quit

# 查看所有会话
screen -ls

# 进入会话
screen -r session_name

# 清除dead会话
screen -wipe