Shell 简介
Shell 基本概念
- 终端: 获取用户输入、展示运算成果的硬件设备。
- tty: teletypeWriter, 早期指的是电传打印机, 现在的 tty 变成一个虚拟的概念, 在 Linux 中是一个程序, 表明 输入/输出 环境。
- 终端模拟器: 每一个终端模拟器会关联一个虚拟 tty, 经过 tty 和体系内核交互。Mac Terminal、iTerm2(也是 mac 上的终端)、GNOME Terminal(Linux 上的) 和 Window Terminal (或许需求下载) 是常见的终端模拟器。
- Shell: command interpreter, 指令解说程序, 用来处理来自终端模拟器的输入、解说履行之后输出成果给终端。
- Bash: Shell 的一种具体完结。此外还有 Zsh、Fish 和 Powershell 等。
Shell 开展
- 1971 年, Ken Thompson 在贝尔实验室为 UNIX 开发了榜首个 shell, 称为 V6 shell。
- 1979 年, Stephen Bourne 在贝尔实验室在 V7 UNIX 发布了 Bourne shell , 即 sh。
- 1989 年, 开源安排 GNU 为了取代 Bourne shell 发布了榜首版 Bourne-Again shell,即 Bash
bash 是 sh 的超集, 可履行大部分 sh 脚本, 并集成了 Korn shell 和 C shell 的功用。
Shell 构成
shell 提供了与内核和设备交互的办法(接口), 还集成软件开发中通用的规划方式(如管道和过滤器), 具备操控流程、循环、变量和指令查找的机制。
shell 是一门指令解说器, 一起也是一门编程言语。
Shell 基础语法
变量
类型 | 效果域 | 声明办法 |
---|---|---|
自界说变量 | 当时 shell | = |
环境变量 | 当时 shell 以及子 shell |
export 或 declare -x
|
体系环境变量 | 一切 shell | 发动主动加载 |
declare
声明变量类型
格局: declare 选项 变量
选项 | 意义 |
---|---|
- |
给变量设定类型特点 |
+ |
撤销变量的类型特点 |
-a |
将变量声明为数组类型 |
-i |
将变量声明为整数型 |
-x |
将变量声明为环境变量 |
-r |
将变量声明为只读变量 |
-p |
输出变量及其被声明的类型 |
示例代码
a.sh
内容:
#!/bin/bash
my_var=123
declare -p my_var
在 bash 终端下运转
$ bash a.sh
declare -x my_var="123
父子 shell
一个 shell 中能够调用另外一个 shell 脚本, 比方:
a.sh
文件内容:
#!/bin/bash
export my_var=123
bash b.sh
b.sh
文件内容:
echo ${my_var}
在 bash 终端下运转
$ bash a.sh
123
自界说变量
#!/bin/bash
# 变量名=变量值 等号左右不能有空格!
page_size=1
page_num=2
# 上面的变量值默许是字符串, 不能进行加减操作
# total=page_size*page_num ❌
# 声明变量为整型
let total=page_size*page_num # 办法1, 运用 let
declare -i total=page_size*page_num # 办法二, 运用 -i 参数
# 变量值是指令
_ls=ls
# 变量值是指令履行成果
file_list=${ls -a}
环境变量
page_size=1
page_num=2
let total=page_size*page_num
# 运用 export 将变量变成环境变量
export total
# 也运用 -x 参数声明为环境变量
declare -x total
体系环境变量
变量名 | 意义 | 常见操作 |
---|---|---|
$0 |
当时 shell 名称/脚本名声 |
$1 , $2 等能够获取到传入参数 |
$# |
传入脚本的参数数量 | if[ $# -gt 1 ] |
$* |
传入脚本的一切参数 | |
$? |
上条指令履行的状况码 | if[ $? -eq 0 ] |
$PS1 |
指令提示符 | export PS1="\u@\h \w> " |
$USER |
用户名 | |
$HOME |
用户主文件夹 | cd ~ |
$PATH |
大局指令的查找途径 | PATH=$PATH:[新增途径] |
PS1="\u@\h \w> "
意义: \u
是用户名; \h
是主机名; \w
是当时目录。
linux 中 $PATH
是运用 分号 :
作为分隔符。
装备文件加载顺序和优先级
体系环境变量是界说在装备文件中的, 装备文件有多个, 不同状况加载的装备文件是不相同的。
shell 能够分为 login shell 和 non-login shell。
login shell 是指用户登录体系时开启的 shell。在 login shell 中, 体系会履行 /etc/profile
文件来初始化环境变量和途径等体系规模的设置, 而且还会读取当时用户的 ~/.bash_profile
或 ~/.profile
文件来设置个人化的环境变量和指令别号等。
non-login shell 是指在登录后经过运转一个新的 shell 脚本而翻开的 shell。这些 shell 不会履行体系规模的设置, 而是直接读取当时用户的 ~/.bashrc
文件来加载个人化的环境变量、指令别号和函数等。
假如修正了装备文件, 不会当即收效, 需求我们重启终端或许履行 source 装备文件
指令
bashrc 只效果在 bash 中。 ~/.bashrc
是用户等级的, /etc/bashrc
是体系等级的。默许状况下用户级的装备文件优先级是高于体系等级的。为什么叫做默许状况下呢? 因为你能够经过 source 装备文件
指令修正这个优先级。具体看示例:
linhieng@LINHIENG:~$ vim ~/.bashrc # 在内容完毕增加 export PS1="\u \w > " 环境变量
linhieng@LINHIENG:~$ source ~/.bashrc # 履行装备文件, 让其收效
# 此刻能够看到效果:
linhieng ~ > sudo vim /etc/profile # 相同, 在内容完毕增加 export PS1="> " 体系环境变量
[sudo] password for linhieng:
linhieng ~ > source /etc/profile # 让其收效
# 此刻能够看到效果, 这说明优先级最高的是最近履行的 source 装备文件, 其次才是默许状况下的优先级
> bash # 在当时 shell 下新建一个子 bash, 它是属于 non-login shell, 所以它会读取 ~/.bashrc, 能够理解为它履行了 source ~/.bashrc
# 故此刻优先级又回到了 "默许状况", 即用户等级优先级高于体系等级优先级
linhieng ~ > exit
exit
# 退出时, 并不会再次履行用户级装备
> source ~/.bashrc
linhieng ~ > source /etc/profile # 能够经过 source 随意切换优先级
>
运算符和引证
类型 | 符号 | ||
---|---|---|---|
算术运算符 |
+ - * / % ` |
& | ` |
逻辑运算符 | ` | &&!` | |
比较运算符 |
== != < >
|
||
引号 |
"" '' ``
|
||
圆括号 |
(()) ()
|
||
指令连接 | ` | &&;` | |
后台运转 | & |
引号和圆括号运用示例
#!/bin/bash
a=0
# 双引号, 部分引证
foo="${a}123"
echo $foo # 0123
# 单引号, 彻底引证, 原样输出
foo='${a}123'
echo $foo # ${a}123
# 反引号, 内容会被认为是可履行的指令
foo=`echo 'hello, world!'`
echo $foo # hello, world!
# 双括号, 算术运算
foo=$((1+2))
echo $foo # 3
# 单括号, 效果同反引号
foo=$(echo 'hi~')
echo $foo # hi~
履行效果如下:
$ bash a.sh
0123
${a}123
hello, world!
3
hi~
关于指令连接, 特别留意一下, 回来码为 0 代表没有过错(和 C 言语相同)。
-
cmd1 || cmd2
: 若 cmd1 履行完而且回来码非 0, 则继续履行 cmd2 -
cmd1 && cmd2
: 若 cmd1 履行完而且回来码 0, 则继续履行 cmd2 -
cmd1 ; cmd2
: 先履行 cmd1 再履行 cmd2。 两者不会相互影响
后台运转的 &
一般调配 nohup
指令一起运用。只运用 &
, 则当当时 shell 封闭后, 程序依旧会封闭。但若调配 nohup
则封闭当时 shell 后, 程序也可继续履行。比方 nohup node index.js &
。
小 Tip: 所谓封闭 shell, 指的是正常封闭, 而不是反常封闭。比方经过 ssh 连接到云服务器后, 若直接封闭当时 shell 窗口, 这种状况属于反常封闭,
nohup
是会失效的。正确封闭的办法是履行exit
指令
管道
管道与管道符 |
, 效果是将前一个指令的成果传递给后边的指令。
语法: cmd1 | cmd2
要求: 管道右侧的指令必须能承受规范输入才行, 比方 grep
, wc
等指令能够直接运用管道符, 而 ls
等则不能直接运用, 需求凭借 xargs
进行预处理
留意: 管道指令仅仅处理 stdout
, 关于 stderr
会予以忽略。不过, 能够运用 set -o pipefail
设置 shell
遇到管道过错退出
下面给出 xargs
的简单示例:
$ cd /usr
$ find . -maxdepth 2 -name "*.sh" # 文件数量太多, 运用 maxdepth 来约束查找目录深度
./bin/gettext.sh
./bin/rescan-scsi-bus.sh
$ find . -maxdepth 2 -name "*.sh" | ls -l # ls 无法承受默许输入, 所以下面输出的成果和 find 的成果无关
total 0
drwxr-xr-x 1 root root 4096 Sep 12 2022 bin
drwxr-xr-x 1 root root 4096 Apr 18 2022 games
drwxr-xr-x 1 root root 4096 Aug 8 2022 include
drwxr-xr-x 1 root root 4096 Sep 12 2022 lib
drwxr-xr-x 1 root root 4096 Aug 8 2022 lib32
drwxr-xr-x 1 root root 4096 Aug 8 2022 lib64
drwxr-xr-x 1 root root 4096 Aug 8 2022 libexec
drwxr-xr-x 1 root root 4096 Aug 8 2022 libx32
drwxr-xr-x 1 root root 4096 Aug 8 2022 local
drwxr-xr-x 1 root root 4096 Sep 12 2022 sbin
drwxr-xr-x 1 root root 4096 Aug 8 2022 share
drwxr-xr-x 1 root root 4096 Aug 8 2022 src
$ find . -maxdepth 2 -name "*.sh" | xargs ls -l # 运用 xargs 对内容进行预处理, 此刻 ls 的输入参数便是 find 的输出了
-rwxr-xr-x 1 root root 5188 Mar 25 2022 ./bin/gettext.sh
-rwxr-xr-x 1 root root 38762 Mar 25 2022 ./bin/rescan-scsi-bus.sh
重定向
重定向输入符号:
-
>
: 掩盖写入文件 -
>>
: 追加写入文件 -
2>
: 过错输出写入文件, 2 表明规范过错,>
相当于省略了前面的 1(规范输出) -
&>
: 正确和过错输出一致写入到文件中
示例:
# 测验 >
$ echo hello > a.txt
$ cat a.txt
hello
$ echo hi > a.txt
$ cat a.txt
hi
# 测验 >>
$ echo hello >> a.txt
$ cat a.txt
hi
hello
# 测验 2>>
linhieng@LINHIENG:~$ abcde >> a.txt
Command 'abcde' not found, but can be installed with:
sudo apt install abcde
linhieng@LINHIENG:~$ abcde 2>> a.txt
linhieng@LINHIENG:~$ cat a.txt
hi
hello
Command 'abcde' not found, but can be installed with:
sudo apt install abcde
# 测验 &>
$ abcde &> a.txt
$ cat a.txt
Command 'abcde' not found, but can be installed with:
sudo apt install abcde
输入重定向符号:
-
<
: 重定向输入, 后边能够接一个文件 -
<<
: 用于在指令行界面中直接输入多行文本作为指令的输入,<<
后边需求接一个中止字符串
示例:
# 测验 <
# wc 输出成果是 " 行数 单词数 字节数 "
$ wc < a.txt
2 13 77
# 测验 <<
$ wc << end
> hello
> how are you
> end.
> end
3 5 23
判别指令
shell 中提供了 test
, [
和 [[
作为判别符号, 他们均可用于判别整数, 字符串和文件。test
和 [
功用单一, 只能运用自己支撑的标志位, <
, >
和 =
只能用来比较字符串, 不能比较整数。而 [[
功用更丰富, 整型能够运用 <
, >
和 =
来比较, 而且字符串中支撑 =~
正则比较。具体语法如下:
test condition
-
[ condition ]
留意中括号内的空格是有意义的, 不能省略 -
[[ condition ]]
同上, 留意空格;
test
示例:
a.sh
文件内容:
#!/bin/bash
n1=1
n2=1
n3=3
# 整数测验
test $n1 -eq $n2 && echo '-eq 表明是否持平(equal)'
test $n1 -lt $n3 && echo '-lt 表明小于(less than)'
test $n3 -gt $n2 && echo '-gt 表明大于(greater than)'
# 字符串测验, 为避免字符串有空格其他分隔符, 应运用双引号包裹字符串
test -z "$str_a" && echo 'zero length. 若字符串为空则放回真(0), 否则回来假(非0)'
str_b=' '
test -n "$str_b" && echo 'non-zero length. 和 -z 相反'
str_a=' '
test "$str_a" = "$str_b" && echo '留意, 独自一个 = 是正确的'
# 文件测验
test -e a.sh && echo 'exits. 判别文件/目录是否存在'
test -f a.sh && echo 'file. 判别是否是一般文件'
在 bash 终端下运转
$ bash a.sh
-eq 表明是否持平(equal)
-lt 表明小于(less than)
-gt 表明大于(greater than)
zero length. 若字符串为空则放回真(0), 否则回来假(非0)
non-zero length. 和 -z 相反
留意, 独自一个 = 是正确的
exits. 判别文件/目录是否存在
file. 判别是否是一般文件
[
和 test
差不多, 就不给出示例了。
[[
示例:
#!/bin/bash
n1=1
n2=2
# 整数测验
[[ $n1 = $n2 ]] ; echo $? # = 或许 == 都是能够的
[[ $n1 < $n2 ]] ; echo $?
[[ $n1 > $n2 ]] ; echo $?
str1="hello world 123"
str2='hello world'
pattern="[0-9]+"
[[ "$str1" =~ $pattern ]] ; echo $? # 正则是字符串, 则需求运用变量方式
[[ "$str2" =~ [0-9]+ ]] ; echo $? # 不运用变量, 可直接写正则
分支句子
if else 语法1
if [ condition1 ] ; then
# execute commands if condition1 is true
elif [ condition2 ] ; then
# execute commands if condition2 is true
else
# execute commands if all above conditions are false
fi
事例:
#!/bin/bash
a=$1
b=$2
if [[ $a > $b ]]
then
echo "$a > $b"
elif [[ $a < $b ]]
then
echo "$a < $b"
else
echo "$a == $b"
fi
运转:
$ bash a.sh 1 2
1 < 2
$ bash a.sh 1 1
1 == 1
$ bash a.sh 2 1
2 > 1
case 语法:
case $variable in:
"pattern1")
# execute commands for pattern1
;;
"pattern2" | "pattern3")
# execute commands for pattern2 or pattern3
;;
*)
# execute commands if no pattern matches
;;
esac
事例:
#!/bin/bash
read -p "Input a number between 1 or 2: " num
case $num in
1)
echo "You entered one"
;;
2)
echo "You entered two"
;;
*)
echo "Invalid input"
;;
esac
运转:
$ bash a.sh
Input a number between 1 or 2: 1
You entered one
$ bash a.sh
Input a number between 1 or 2: 2
You entered two
$ bash a.sh
Input a number between 1 or 2: a
Invalid input
循环句子
while 循环
语法:
while [ condition ]
do
# command
done
示例:
#!/bin/bash
count=1
while [[ $count < 5 ]]
do
echo "Count is $count"
count=$((count + 1))
done
运转:
$ bash a.sh
Count is 1
Count is 2
Count is 3
Count is 4
until 循环
语法:
until [ condition ]
do
# command
done
示例:
#!/bin/bash
count=1
until [[ $count > 5 ]]
do
echo "Count is $count"
count=$((count + 1))
done
运转:
$ bash a.sh
Count is 1
Count is 2
Count is 3
Count is 4
Count is 5
for 循环
语法:
for variable in list
do
# command
done
示例:
#!/bin/bash
for i in 1 2 3 4 5
do
echo "Number: $i"
done
运转:
$ bash a.sh
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
函数
语法1:
function function_name() {
parameter1=$1
parameter2=$2
# ...
# commands
}
# 调用
function_name parameter1 parameter2 ...
语法2:
function_name() {
parameter1=$1
parameter2=$2
# ...
# commands
}
# 调用
function_name parameter1 parameter2 ...
示例1:
#!/bin/bash
printName() {
if [[ $# < 2 ]] ; then
echo 'illegal parameter.'
exit 1 # 这不是回来值, 而是直接完毕脚本的运转
fi
echo "firstName: $1"
echo "lastName: $2"
}
printName jacky chen
printName $1 $2
运转:
$ bash a.sh JK lin
firstName: jacky
lastName: chen
firstName: JK
lastName: lin
$ bash a.sh JK
firstName: jacky
lastName: chen
illegal parameter.
示例2:
#!/bin/bash
f() {
echo 666
return $1
}
f 255
echo "履行状况: $?" # 255
f 256
echo "履行状况: $?" # 256 溢出, 成果为 0
r=$(f 256)
echo "履行成果: $r"
f
echo "履行状况: $?"
运转:
$ bash a.sh
666
履行状况: 255
666
履行状况: 0
履行成果: 666
示例3:
#!/bin/bash
f() {
test -n "$1"
}
f $1
echo "履行状况: $?"
运转:
$ bash a.sh
履行状况: 1
$ bash a.sh 1
履行状况: 0
示例4:
#!/bin/bash
f1() {
a=66
}
f1
echo "a: $a" # 66, 被函数内的变量污染了
f2() {
local b=77
}
f2
echo "b: $b" # 无输出, 没有被污染
f3() {
c=77
unset c
}
f3
echo "c: $c" # 无输出, 没有被污染
运转:
$ bash a.sh
a: 66
b:
c:
留意:
- shell 自上而下履行, 函数必须在运用前界说
- 函数获取形参是运用
$1
$2
… 这种办法, 而且不需求再括号内声明 - 函数内 return 仅仅表明函数履行状况, 不代表函数履行成果。回来值是一个 8 位的状况码, 它的最大值是 255。
- 想要获取函数回来的成果, 可经过
echo
,printf
, 不要经过 return 的办法 - 假如没有 return, 函数回来的状况函数内终究一条句子的履行状况
- 为了函数内界说的变量不污染大局, 最好在函数内运用 local 去界说, 或许在函数退出之前运用 unset 去处理一下
模块化
模块化的原理是在当时 shell 内履行函数文件, 具体是运用 source 函数库途径
来完结模块化。
事例:
math.sh
文件:
#!/bin/bash
# add function
# @return platForm
add() {
declare -i res=$1+$2
echo $res
}
a.sh
文件:
#!/bin/bash
source './math.sh'
total=`add $1 $2`
echo $total
运转:
$ bash a.sh 66 666
732
shell 常用指令
更具体的运用, 可履行 指令 --help
进行检查。
指令 | 说明 | |
---|---|---|
grep |
global regular expression print, 文本查找东西 | |
sort |
文本排序。 指定分隔符后以第三列进行排序: sort -t ' ' -k 3
|
|
wc |
核算出现的行数、单词数、字符数 | |
head |
检查最初若干行, 默许 10 行 | |
tail |
检查完毕若干行。在实时跟踪日志时特别有用: tail -f -n 10 xx.log
|
|
cut |
对数据行的内容进行处理。以空格为分隔检查第三个 `cat a | cut -d ‘ ‘ -f 3` |
find |
文件和目录查找 | |
xargs |
参数处理 | |
which |
查找指令途径 |
Shell 履行过程和原理
履行
shell 脚本一般以 .sh 完毕, 也能够没有, 这是一个约好; 榜首行需求指定用什么指令解说器来履行。
脚本以 #!
最初时, 操作体系(内核)会主动查找该行后边指定的解说器, 并运用它来运转该脚本。
#! /bin/bash
#! /usr/bin/env bash
脚本能够有三种发动办法:
# 文件名运转, 留意前缀 ./ 不能省略, 否则会辨认为指令, 而不是文件
./xx.sh
# 解说器运转, 这儿能够省略 ./
bash xx.sh
# source 运转
source xx.sh
履行过程
- 字符解析
- 辨认换行符、 分号(
;
) 做行的切割 - 辨认指令连接符(
||
&&
|
) 做指令的切割 - 辨认空格、tab符, 做指令和参数的切割
-
shell 打开, 例如
{1..3}
解析为1 2 3
-
重定向, 将
stdin
,stdout
,stderr
的文件描述符进行指向变更 -
履行指令
-
builtin
直接履行 - 非
builtin
运用$PATH
查找, 然后发动子进程履行
builtin
指的是内置指令
- 收集状况并回来
shell 的架构图类似于一个流水线, 在里面进行输入分析和解析。bash 会以一特殊字符作为分隔符, 将文本进行分段解折。在 bash 脚本中是以回车或许分号作为一行命今完毕的标志, 这便是榜首层级的解折, 将大段的命今行进行分段符号拓宽(运用各种办法, 比方大括号 {}
、波浪符 ~
、变量和参数的打开/替换、文件名打开), 并终究履行命今(经过 shell 内置命今或外部命今)。
Shell 打开
大括号打开 Brace Expansion
一般由三部分构成: 前缀, 一对大括号和后缀。大括号内能够是逗号切割的字符串序列, 也能够是序列表达式 {x..y[..increase]}
# 字符串序列
a{b,c,d}e => abe ace ade
# 表达式序列, 数字能够运用 increase 调整增量, 但字母不行
{1..5} => 1 2 3 4 5
{1..5..2} => 1 3 5
{a..e} => a b c d e
波浪号打开 Tilde Expansion
# 当时用户主目录
~ => $HOME
# 指定用户主目录
~lin/foo => 用户 lin 的 $HOME/foo
# 当时工作目录
~+/foo => $PWD/foo
# 上一个工作目录
~-/foo => ${$OLDPWD-'~-'}/foo
参数打开 Shell Parameter Expansion
-
间接参数扩展
${!parameter}
, 类似于指针的指针#!/bin/bash var='hello' parameter='var' echo ${parameter} # var echo ${!parameter} # hello
-
参数长度
${#parameter}
#!/bin/bash var='hello' echo ${#var} # 5
-
空参数处理
-
${a:-word}
: 若 a 为空, 则成果为 word -
${b:=word}
: 若 b 为空, 则成果为 word, 而且 b=’word’ -
${c:?word}
: 若 c 为空, 则报错并退出 -
${d:+word}
: 若 d 不为空, 则成果为 word
事例:
#!/bin/bash b=${a:-word} echo "a: $a b: $b" # a: b: word d=${c:=word} echo "c: $c d: $d" # c: word d: word g='haha' h=${g:+word} echo "g: $g h: $h" # g: haha h: word f=${e:?word} # a.sh: line 13: e: word echo "this isn't echo" # 不会输出, 因为现已报错退出了
运转:
$ bash a.sh a: b: word c: word d: word g: haha h: word a.sh: line 17: e: word
-
-
参数切片
-
${a:offset:length}
: 从第 offset 个字符(不包含offset)开端, 截取 length 个 -
${a:offset}
: 没写 length, 默许截取到终究
#!/bin/bash a='abcdefg' echo ${a:2} # cdefg echo ${a:2:3} # cde
-
-
参数部分删除
-
${parameter%patter}
最小程度从后边截取 patter -
${parameter%%patter}
最大程度从后边截取 patter -
${parameter#patter}
最小程度从前面截取 patter -
${parameter##patter}
最大程度从前面截取 patter
所谓的最大程度和最小程度, 只有和正则相结合时才有效果, 假如 patter 只是一个字符串, 那么最大程度和最小程度都是相同的。
#!/bin/bash a='111' echo ${a%1} # 11 echo ${a%%1} # 11 echo ${a#1} # 11 echo ${a##1} # 11 b='hello-world-helloo' echo ${b%-*} # hello-world echo ${b%%-*} # hello echo ${b#*-} # world-helloo echo ${b##*-} # helloo
-
指令替换 Command Substitution
有两种方式, 也便是前面说到的 $(...)
和 ``
数学核算 Arithmetic Expansion
即前面说到的 $(())
文件名打开 Filename Expansion
() * ? []外壳文件名方式匹配
当有单词没有被引号包裹, 且其中出现了 *
, ?
, []
, {}
字符, 则 shell 会去依照正则匹配的办法查找文件名进行替换, 假如没找到则保持不变。
-
*
: 匹配恣意数量的恣意字符。 -
?
: 匹配单个恣意字符。 -
[]
: 匹配一组指定规模内的恣意字符。 -
{}
: 扩展为逗号分隔的恣意字符串列表。
#!/bin/bash
echo ?.*
echo *[.]*
echo {a,b}.txt
$ bash a.sh
a.js a.sh a.txt b.txt
a.js a.sh a.txt b.txt index.html math.sh package.json package-lock.json test.js
a.txt b.txt
调试和前端集成
这部分只做引子, 暂时不会给出具体事例
调试
- 打印输出。运用 echo, printf 指令
- 运用 set 指令。一般会在最初增加
set -uxe -o pipefail
装备。
set 指令用于设置和修正 shell 的选项和参数。
-u
参数效果是 “遇到不存在的变量就会报错, 并中止履行”;-x
效果 “运转成果之前, 先输出履行的那一行指令”;-e
效果 “只要发生过错, 就中止履行”;-o pipefail
效果 “管道符连接的时, 只要一个子指令失利, 则整个管道指令就失利, 脚本会中止履行”
- 利用vscode debug 插件
- 安装插件(1必选3可选): Bash Debug 支撑单步调试; 还有三个可选的插件: shellman 用于代码提示和主动补全, shellcheck 代码语法校验, shell-format 代码格局化。
- 编写 launch.json 装备文件
- 确保 bash 在 4.x 以上版本。可经过
bash --version
检查版本
前端集成
在前端中也能够运用 shell 指令做相关操作。
-
node 中经过
exec
或spawn
调用 shell 指令。这两个函数均在child_process
包中。-
exec
发动一个子 shell 进程履行传入的指令, 而且将履行成果保存在缓中区中, 而且缓中区是有巨细约束(200KB)的, 履行完毕经过回调函数回来。 -
spawn
默许不运用 shell, 而是直接发动子进程履行指令, 且会直接回来一个流目标, 支撑写入或许读取流数据, 这个在大数据量交与的场景比较适合。
-
-
shell 脚本中调用 node 指令
#! /bin/bash node ./exec.js echo 'exec.js running'
-
凭借 zx 等库进行 javascript, shell script 的融合
- 凭借 shell 完结体系操作, 比方文件io, 内存, 盘体系状查询等
- 凭借 nodejs 完结应用层才能, 比方网络io, 核算等
#!/usr/bin/env zx // 经过 $`command` 来调用 shell let files = await $`ls -a | grep node` console.log( chalk.blue(`files: ${files}.`)) await sleep(1000) await fetch('https://google.com') let answer = await question('do you want to create new dir ?') if (answer === 'y') { await $`mkdir temp_dir` }
课程总结