Zsh/Bash startup files loading order (.bashrc, .zshrc etc.)
+----------------|-----------|-----------|------+
| |Interactive|Interactive|Script|
| |login |non-login | |
+----------------|-----------|-----------|------+
|/etc/profile | A | | |
+----------------|-----------|-----------|------+
|/etc/bash.bashrc| | A | |
+----------------|-----------|-----------|------+
|~/.bashrc | | B | |
+----------------|-----------|-----------|------+
|~/.bash_profile | B1 | | |
+----------------|-----------|-----------|------+
|~/.bash_login | B2 | | |
+----------------|-----------|-----------|------+
|~/.profile | B3 | | |
+----------------|-----------|-----------|------+
|BASH_ENV | | | A |
+----------------|-----------|-----------|------+
| | | | |
+----------------|-----------|-----------|------+
| | | | |
+----------------|-----------|-----------|------+
|~/.bash_logout | C | | |
+----------------|-----------|-----------|------+
对于 zsh
+----------------|-----------|-----------|------+
| |Interactive|Interactive|Script|
| |login |non-login | |
+----------------|-----------|-----------|------+
|/etc/zshenv | A | A | A |
+----------------|-----------|-----------|------+
|~/.zshenv | B | B | B |
+----------------|-----------|-----------|------+
|/etc/zprofile | C | | |
+----------------|-----------|-----------|------+
|~/.zprofile | D | | |
+----------------|-----------|-----------|------+
|/etc/zshrc | E | C | |
+----------------|-----------|-----------|------+
|~/.zshrc | F | D | |
+----------------|-----------|-----------|------+
|/etc/zlogin | G | | |
+----------------|-----------|-----------|------+
|~/.zlogin | H | | |
+----------------|-----------|-----------|------+
| | | | |
+----------------|-----------|-----------|------+
| | | | |
+----------------|-----------|-----------|------+
|~/.zlogout | I | | |
+----------------|-----------|-----------|------+
|/etc/zlogout | J | | |
+----------------|-----------|-----------|------+
用分号或换行符. 即:
cmd1; cmd2
以 #
符号及之后的行内容都是注释
双引号的字符串则会进行变量替换
单引号的字符串则不会进行变量替换
默认情况下, 会自动添加换行
-n
参数: 忽略结尾的换行
-e
参数: 表示包含转义序列
30 黑色
31 红色
37 白色
echo "\e[1;31m Hello World\e[0m"
40 黑色
41 红色
47 白色
echo "\e[1;42m Hello World\e[0m"
printf
与 C 语言中的 printf
函数参数一样.
默认情况下, 不会自动添加换行
在 Bash 中, 每一个变量的值都是字符串, 无论你给变量赋值时有没有使用引号, 值都会以字符串的形式存储.
有一些特殊的变量会被Shell环境和操作系统用来存储一些特别的值, 这类变量就称为 环境变量
终端环境变量
使用 env
命令查看.
进行的环境变量
cat /proc/$PID/environ
上面返回的是变量的列表, 以 name=value
的形式来描述. 之间由 \0
分隔. 可将 \0
替换为 \n
就可使每一行显示了.
cat /proc/$PID/environ | tr '\0' '\n'
var=value
注意, 它不同于
var = value
前者才是赋值, 后者是相等操作.
引用变量的值
${var}
注意, 如果包含在单引号里, 变量不会被扩展. 将依照原样显示.
获取变量的长度
length=${#var}
获取当前的SHELL
echo $0
echo $SHELL
检查是否 root 用户
if [ $UID -ne 0 ]; then
echo "Non root user"
echo "root user"
修改提示符字符串
在文件 ~/.bashrc
中的某一行的 PS1
变量中设置的.
Bash 中进行数学运算
使用let时, 变量名之前不需要添加 $
, 例如:
no1=4
no2=5
let result=no1+no2
echo $result
自加和自减,缩写
let no1++
let no1--
let no1+=6
let no1-=6
使用 []
result=$[ no1 + no2 ]
result=$[ $no1 + 5 ]
使用 (())
这种变量名之前要加上 $
result=$(( no1 + 50 ))
使用 expr
result=`expr 3 + 4`
result=$(expr $no1 + 5)
浮点运算 bc
echo "4 * 0.45" | bc
echo "scale=2; 3/8" | bc
echo "obase=2; 1000" | bc
obase
: 输出进制
ibase
: 输入进制
文件描述符
文件描述符是一种用于访问文件的抽象指示器. 存取文件离不开被称为 文件描述符
的特殊数字.
0 : 标准输入 stdin /dev/stdin
1 : 标准输出 stdout /dev/stdout
2 : 标准错误 stderr /dev/stderr
自定义文件描述符
文件打开模式通常有3种
< : 从文件中读取内容到 stdin
> : 用于截断模式写入
>> : 用于追加模式写入
创建一个文件描述符进行读取:
exec 3<input.txt
这表示使用文件描述符3打开并读取文件.
使用文件描述符
cat <&3
注意, 只能读取一次, 若要再次读取, 则要重新使用 exec 来分配文件描述符进行二次读取.
exec 4>output.txt
echo "ehllo" >&4
exec 5>>output.txt
echo "hello" >&5
注意, 是使用 >&5
> : 旧内容会被清空, 然后设置为新的内容. 这等同于 1>
>> : 追加到旧内容尾部. 这等同于 1>>
< : 用于从文件中读取内容到 stdin
将 stderr
和 stdout
分别重定向到一个文件:
cmd 2>stderr.txt 1>stdout.txt
stderr
和 stdout
一起重定向:
cmd 2>&1 output.txt
忽略错误输出:
cmd 2>/dev/null 1>output.txt
同时重定向到文件和 stdout
command | tee FILE2 FILE2
注意, tee
只能读取 stdout
而不包括 stderr
使用 stdin
作为命令行参数:
cmd 1 | cmd2 | cmd3 -
即 -
作为命令的文件名参数即可.
多行文件重定向
cat << EOF > log.txt
这里是内容
理解: stackoverflow.com
这表示, 指示 shell 直接从当前源中读取输入, 直到有一行的内容仅包含 EOF 这个单词.
命令的成功与否
echo $?
如果返回0, 表示上一个命令执行成功, 否则是失败.
起始索引为0.
array_var=(1 2 3 4 5 6)
echo ${array_var[0]}
打印数组所有值
echo ${array_var[*]}
echo ${array_var[@]}
echo ${#array_var[*]}
declare -A ass_array
ass_array=([key1]=value [key2]=value2)
ass_array[key1]=value1
ass_array[key2]=value2
echo ${ass_array[key]}
列出数组索引
echo ${! ass_array[*]}
echo ${! ass_array[@]}
alias new_command='command sequence'
永久保存: 将内容写到 ~/.bashrc
alias new_command=
unalias new_command
日期和时间
纪元时或 Unix 时间: UTC 1970年1月1日 0时0分0秒起所流逝的秒数.
打印纪元时
date +%s
从指定时间转换为纪元
date --date "Thu Nov 18 08:07:21 IST 2010" +%s
--date
用于提供日期字符串作为输入.
获取星期几
date --date "Jan 20 2001" +%A
格式化日期
格式化占位符列表
date "+%d %B %Y"
设置日期和时间
date -s "格式化的日期字符串"
bash -x script.sh
在脚本内部, 进行部分调试
set -x
要调试的代码段
set +x
-x
: 执行时显示命令和参数
+x
: 禁止调试
-v
: 当命令进行读取时显示输入
+v
: 禁止打印输入
function fname() {
statements;
fname() {
statements;
fname;
fname arg1 arg2;
function fname(){
echo $1, $2 # 访问参数1, 参数2
echo "$@" # 以列表的方式一次性打印所有参数
echo "$*"; # 类似 $@, 但是参数被作为单个实体
return 0; # 返回值
$1
是第一个参数
$2
是第二个参数
$n
是第n个参数
$@
被扩展为”$1” “$2” “$3” 等
$*
被扩展成 “$1c$2c$3”, 其中c是IFS的第一个字符
$@
用的比 $*
多, 因为 $*
将所有参数当作单个字符串, 因此它很少被使用
bash 支持递归调用
函数也可以像环境变量一样用 export
导出, 如此一来, 函数的作用域就可以扩展到子进程中. 例如
export -f fname
读取命令返回值(状态)
echo $?
$?
会给出命令 cmd 的返回值. 这个返回值被称为退出状态.
命令输出读入到变量
# 这种方法称为子shell
cmd_output=$(COMMANDS)
# 这种方法称为 反引用
cmd_output=`COMMANDS`
子shell
(cd /bin ; ls);
第二行中的语句即为子shell, 它不会对当前shell有任何影响.所有改变仅限于子shell内.
保留空格和换行
利用子shell或反引用的方法将命令的输出读入到一个变量中, 可以将它放在双引号中, 即可保留空格和换行符.
out=$(cat file.txt)
out1="$(cat file.txt)"
注, 像好这个没有效果. 我在 Ubuntu 16.04.2 LTS , GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu) 版本中测试没有效果. 有待处理.
read 命令
读取 N 个字符到变量
read -n N var_name
用无回显的方式读取密码
read -s var
显示提示信息
read -p "enter input:" var
在特定时限内读取
read -t timeout var
用特定的定界符作为输入行的结束
read -d delim_char var
true 的命令
它是内建命令, 总是会返回为0的退出码.
字段分隔符 IFS
IFS 是存储定界符的环境变量, 它是当前 shell 环境使用的默认定界字符串.
它的值, 默认为 空白字符
#!/bin/bash
data="1,2,3,4,5"
oldIFS=$IFS
IFS=,
for item in $data;
echo Item: $item
IFS=$oldIFS
./hello.sh
Item: 1
Item: 2
Item: 3
Item: 4
Item: 5
for 循环
for var in list;
commands;
list
可以是字符串, 也可以是一个序列.
{1..50}
表示从1到50的数字列表.
{a..z}
for 的 c 风格
for ((i=0;i<10;i+)) {
commands;
while 循环
while condition
commands;
until 循环
until condition;
commands;
if condition;
commands;
if .. elif .. else
if condition;
commands;
elif condition; then
commands;
commands;
[ $var -eq 0 ]
注意, 中括号与操作数之间要有空白.
-gt : 大于
-lt : 小于
-ge : 大于等于
-le : 小于等于
[ $var -ne 0 -a $var2 -gt 2 ] # 表示逻辑与, -a
[ $var -ne 0 -o $var2 -gt 2 ] # 表示逻辑或, -o
文件系统测试
[ -f $file_var ] # 如果是正常的文件路或文件名
[ -x $var ] # 如果给定的变量包含的文件可执行, 则返回真
[ -d $var ] # 如果是目录
[ -e $var ] # 如果文件存在
[ -c $var ] # 如果是字符设备
[ -b $var ] # 如果是块设备
[ -w $var ] # 如果文件可写
[ -r $var ] # 如果文件可读
[ -L $var ] # 如果是符号链接
字符串比较
最好使用双中括号
[[ $str1 = $str2 ]] # 如果相等
[[ $str1 == $str2 ]] # 如果相等
[[ $str1 != $str2 ]] # 如果不相等
[[ $str > $str2 ]] # 大于
[[ $str < $str2 ]] # 小于
[[ -z $str1 ]] # 如果是空字符串
[[ -n $str1 ]] # 如果是非空字符串
[[ -n $str1 ]] && [[ -z $str2 ]]
test 命令
if [ $var -eq 0 ]; then
echo "True";
与可以写为
if test $var -eq 0; then
echo "True";
-s : 压缩多行空行为一行空行
-T : 显示制表符
-n : 显示行号
-b : 显示行号, 但不为空白行设置行号
find 命令
find base_path -print0
-print0 表示以 ‘\0’ 作为文件名的界定符. 默认为换行符, 但当文件名包含换行符时, 这就有用了. 注意, 是连起来的 -print0
-name “*.txt” 正则匹配.
-iname “*.txt” 忽略大小写
find . \( -name "*.txt" -o -name "*.pdf" \) -print
find . ! -name "*.txt" -print
表示匹配所有不以 *.txt
结尾的文件名.
基于目录深度
默认情况下, find 会遍历所有子目录.可以添加选项来限定深度.
-maxdepth
-mindepth
这两个参数应该是 find 的第三个参数, 否则可能会影响效率.
根据文件类型搜索
-type d 目录类型
-type f 文件类型
-type l 符号链接类型
-type c 字符设备
-type b 块设备
-type s 套接字
-atime : 用户最近一次访问时间
-mtime : 文件内容最后一次修改时间
-ctime : 文件元数据最后一次改变的时间
后接 +N 或 -N
单位是天. 负号表示是小于, 正号表示大于
-amin : 访问时间
-mmin : 修改时间
-cmin : 变化时间
这些同上, 只是时间单位为分.
-size +2K : 表示大于 2KB 的文件
-size -2K : 表示小于 2KB 的文件
b : 512 字节
c : 字节
w : 2字
k : 1024 字节
M : 1024 K 字节
G : 1024 M 字节
-delete
-perm 664
-exec
find . -type f -exec cat {} \;> outout.txt
exec 不支持执行多命令, 但可以变换一个, 将命令写入脚本, 然后调用
-exec ./commands.sh {} \;
tr 命令
tr [options] set1 set2
tr -d '[set1]'
tr -s ' '
将多个空白压缩为一个.
md5sum filename
sh1sum filename
crypt
它是一个简单的加密工具, 从 stdin 接受一个文件以及口令作为输入, 然后将加密数据输出到 stdout
crypt < input_file > output_file
crypt -d < encrypted_file > output_file
gpg -c filename
gpg filename.gpg
base64
base64 filename > outputfile
base64 -d file > outputfile
filename=`mktemp`
dirname=`mktemp -d`
仅生成文件名, 而不是实际的文件
tempfile=`mktemp -u`
根据模板创建
mktemp test.XXX
它会生成 test.XXX
形式的临时文件.
提取文件名和扩展名
file_jpg="sample.jpg"
fileName=${file_jpg%.*}
suffixName=${file_jpg#*.}
注意, 单个 %
是非贪婪操作, 想要贪婪式的, 则使用 %%
类似的, 还有 #
是非贪婪的, 而 ##
是贪婪的.
在循环里的命令, 使用 &
时, 它就会直接向下再执行了, 而不会等待命令执行完成.这样子就可以利用多核
#!/bin/bash
PIDARRAY=()
for file in File1.iso File2.iso
md5sum $file &
PIDARRAY+=("$!")
wait ${PIDARRAY[@]}
注意, 还要用 wait 来等待多进程的退出.
dd 命令
dd if=/dev/zero of=data.file bs=1M count1
不可删除的文件
chattr +i file
删除的时候, 它会提示
rm: remove write-protected regular empty file 'file'?
恢复为可删除
chattr -i file
diff 与文件补丁 patch
diff -u version1.txt version2.txt > version.patch
patch 命令可将修改应用于任意文件. 当应用于 version1.txt
时, 就可以得到 version2.txt
, 当应用于 version2.txt
时, 就可以得到 version1.txt
patch -p1 version1.txt < version.patch
patch -p1 version1.txt < version.patch
递归的形式来处理目录及文件
diff -Naur dir2 dir2
快速定位目录
pushd 压入
popd 弹出
dirs 查看栈的内容
cd - 返回上一次的目录
它是一个处理LIFO的数据结构. 目录被存储在栈中, 然后 push 和 pop 进行切换.
wc 命令
wc -l file # 统计文件 file 的行数
wc -w file # 单词数
wc -c file # 字符数
wc file # 行数, 单词数, 字符数
wc file -L # 最长一行的长度
可视化正则
| 正则 | 描述 |
|--------|---------------------------------|
| ^ | 行起始标记 |
| $ | 行结尾标记 |
| . | 任意一个字符 |
| [] | 在 [] 中的任意一个字符 |
| [^] | 在 [^] 之外的任意一个字符 |
| [-] | 在 [-] 指定范围内的任意一个字符 |
| ? | 匹配之前的项1次或0次 |
| + | 匹配之前的项1次或多次 |
| * | 匹配之前的项0次或多次 |
| () | 创建一个用于匹配的子串 |
| {n} | 匹配之前的项n次 |
| {n, } | 匹配之前项至少n次 |
| {n, m} | 匹配之前项n到m次 |
| \ | 转义 |
| 一竖 | 匹配两边任意一项 |
cut 命令
提取指定列
cut -f 2,3 filename
这列表只显示第2,3列
排除指定列
cut -f3 --complement filename
这表示除第3列之外的所有列.
指定界定符
cut -d ";" filename
指定字段的字符或字节范围
cut -c1-5 filename
表示只打印前1~5个字符.
sed 命令
stream editor
替换字符串
sed 's/pattern/replace_string/' file
应用到文件
sed -i 's/pattern/replace_string/' file
默认情况下, sed 将在每一行的第一处符合的内容替换. 要全部则:
sed 's/pattern/replace_string/g' file
只在第N处开始替换
sed 's/pattern/replace_string/2g' file
除了 /
还可以:
sed 's:text:replace:g'
sed 's|text|replace|g'
移除空白行
sed '/^$/d' file
awk '{BEGIN {print "start"} pattern {commands} END {print "end"}}' file
处理流程:
执行 BEGIN {commands} 语句块中的语句
从文件或stdin 中读取一行, 然后执行 pattern {commands} , 重复这个过程, 直接文件全部被读取完.
当读至输入流末尾时, 执行 END {commands} 语句块.
NR : 当前行号
NF : 当前行的字段数
$0 : 当前行的内容
$1 : 第一个字段的内容
$2 : 第二个字段的内容
将外部变量传递给 awk
awk -v VAR=$OUT_VAR '{print VAR}'
设置字段界定符
awk -F: '{print $1}'
这样子, 就将字符界定符设置为 :
了.
gnu awk
length(string) : 返回字符串的长度
paste 命令:列拼接
cat 是按行拼接的.
paste 则是按列来拼接的.
逆序显示. cat 的逆单词.
命令行下载工具
指定多个下载
wget URL1 URL2
指定输出文件
wget URL1 -O outputfile -o logfile
wget -t 5 URL1
为0时, 表示无限重试.