byodian / all-in-github

Manage All Personal Data with Github
https://all-in-github-byodian.vercel.app
MIT License
2 stars 0 forks source link

shell101 #18

Open byodian opened 2 years ago

byodian commented 2 years ago

Shell 脚本基础的概念是一系列命令的列表,列表中的命令按照顺序执行。结构良好的 Shell 脚本还应该有注释(使用前置符号 # )描述步骤。

Shell 脚本文件扩展以 .sh 结尾,文件开头使用 shebang 构造提示系统一个 shell 脚本将要开始。

#!/bin/bash 

Shell 毕竟是一门真正的编程语言,所以 Shell 脚本应该由变量、控制结构等完成。但不论 shell 脚本如何复杂,它都是一系列按照顺序执行的命令集合。

The shell is, after all, a real programming language, complete with variables, control structures, and so forth. No matter how complicated a script gets, it is still just a list of commands executed sequentially.

可以在执行命令的同时向程序传递参数:

bashuser:~$ echo hello
hello

执行步骤

  1. Shell 基于空格分割命令并进行解析;
  2. 执行第一个单词代表的程序,后续单词作为参数传递给程序;

也就是说,个参数中如果存在空格会被当做多个参数处理,使用以下任意一种方式可以使用带空格参数:

Shell 如何寻找 dateecho 等命令?

类似与 Python 或 Ruby,Shell 是一个编程环境,它具备变量、条件、循环或函数。

当执行命令时,实际上我们是在执行一段 shell 可以解释执行的简短代码。在 shell 中执行某条指令,它会咨询环境变量 $PATH ,并列出进行程序搜索的路径:

bashuser:~$ ehco $PATH
/home/bashuser/.local/bin:/home/bashuser/.nvm/versions/node/v12.18.4/bin
bashuser:~$ which echo
/usr/bin/echo
bashuser:~$ /bin/echo hello
hello

$PATH 中搜索由: 所分割的一系列目录,基于名字搜索该程序。找到就执行该程序。

确定某个指令名所代表的程序,可以使用 which 命令。

导航

shell 中的路径是一组被分割的目录,在 Linux 系统中使用 / 分割,Windows 中用 \ 分割。

绝对路径以 / 开头,相对路径是指相对于当前工作目录的路径。

配置 Shell 提示符

显示各种有用的信息

Shell 程序中的流概念

数据流重定向(redirect),将数据传到给其他地方。在 Shell 中,程序有两个主要的流:输入流和输出流。

数据流重定向的作用

将 stdout 与 stderr 分别存到不同的文件夹

find /home -name .bashrc > list_right 2> list_error

以上两个文件的建立方式

dev/null 垃圾桶设备与特殊写法

如果我知道错误讯息会发生,所以要将错误讯息忽略掉而不显示或储存呢?/dev/null 可以吃掉任何导向这个设备的信息喔

find /home -name .bashrc 2> /dev/null

将正确与错误数据通通写入同一个文件

find /home -name .bashrc > list 2>&1 list
find /home -name .bashrc &> list

standard input

< 将原本需要由键盘输入的数据,改由文件内容来取代

cat > catfile < ~/.bashrc 

<< 表示结束的输入字符,举例我们要用 cat 直接将输入的信息输出到 catfile 中,且当键盘输入 eof 时,该输入就会结束,此时与 > 做对比, < 输入需要使用快捷键 crtl + d 结束输入。

$ cat > catfile << "eof"
> This is a good idea
> Hello world
> eof
$ cat catfile
This is a good idea
Hello world

命令执行的判断依据

; 连续执行

$? (指令回传值) 与 &&||

指令执行结果正确,回传一个 $? = 0

指令执行结果错误,回传一个 $? ≠ 0

命令是一个一个执行,command1 && command2 || command3

管道命令

管道命令仅能处理经由前面一个命令传来的正确信息,也就是标准输出的信息,对于标准错误并没有直接处理的能力。

command1 | command2 | command3

在每个管道命令后面接的第一个数据必定是命令,而这个命令必须要能够接受标准输入的数据才行,这样的命令才可以是管道命令。例如,less、head、tail、more 等都是可以接受 STDOUT,而 ls、cp、mv 则不是

!/bin/sh

#!/bin/sh
curl --head -=silent https://missing.csail.mit.edu

# 在 shell 中代表注释,而 ! 具有特殊的含义。

References

byodian commented 2 years ago

Bash

赋值语法 foo=bar,访问变量中存储的数值,其语法为 $foo 。使用空格分隔赋值语句,导致不能正常工作。在 Shell 脚本中使用空格会起到分割参数的作用。

# 此语句不能正常工作
foo = bar

Bash 中的字符串通过 ''' 分隔符来定义。但含义却不同,

foo=bar
echo "$foo"
# 打印 bar
echo '$foo'
# 打印 $foo

参数

bash 使用了很多特殊变量表示参数、错误代码和相关变量。

操作符

&&||

命令替换

以变量的形式获取一个命令的输出

$( CMD ) 执行 CMD 命令,输出结果会替换掉 $( CMD )

bashuser~$ echo "We are in $(pwd)"
We are in /home/bashuser

进程替换

<( CMD ) 会执行 CMD 并将结果输出到一个临时文件中,并将 <( CMD ) 替换成临时文件名。

返回值会通过文件而不是 STDIN。

显示文件夹 foobar 中文件的区别。

bashuser~$ diff <(ls foo) <(ls bar)

通配符

配置文件

Bash is the GNU shell, when the shell is started, it reads its configuration files. The most important are:

文件夹加入环境变量

export PATH="$PATH:~/scripts"

执行 shell 脚本

脚本应该具有执行权限,更改文件权限使用命令:

chmod +x script_name.sh
# 脚本所在的文件夹没有被加入环境变量时
./script_name.sh

# 指定特殊的 shell 执行脚本
sh script_name.sh

bash script_name.sh

这种执行方式会建立一个 subshell。脚本中的函数、变量和 aliases 只能在此 subshell 中访问到,当 subshell 退出并且父级 shell 获取到控制权后,脚本中所有的内容都会被清空,并且忘记脚本所做的更改。

如果你不想开始一个新的 shell 而是希望这个脚本在当前 shell 中被打开,你应该使用:

source script_name.sh

此命令不需要脚本具有执行权限,命令可以在当前环境中被执行。这时脚本中定义的变量,在当前环境中就可以被访问到。

$ source script.sh

Debugging Bash scripts

Debugging on the entire script

执行脚本的命令中,添加 -x 选项将会 debug 整个脚本文件

bash -x script_name.sh

Debugging on part(s) of the script

在脚本文件的某一命令行前后添加 set -xset +x 即可 debug 该命令行。

set -x  # activate debugging from here

set +x  # stop debugging from here

使用 echo 命令调试脚本

在你的代码中插入 echo 语句,这会帮助你辨别错误在哪里发生并且变量的值是什么

#!/bin/bash
echo "Value of variable x is: $x"

set -e option

通过使用 set -e 选项,在遇到错误时,脚本会立即结束执行。通过这种方式也可以帮助我们快速发现问题。

The Bash environment

Shell initialization files

/etc/profile

/etc/bashrc

You might also find that /etc/profile on your system only holds shell environment and program startup settings, while /etc/bashrc contains system-wide definitions for shell functions and aliases. The /etc/bashrc file might be referred to in /etc/profile or in individual user shell initialization files.

Individual user configuration files

~/.bash_profile

This is the preferred configuration file for configuration user environment individually. In this file, users can add extra configuration options or change default settings:

~/.bash_login

~/.bash_profile 不存在时,此文件会被读取

~/.profile

~/.bash_profile 和 ~/.bash_login 不存在时,此文件会被读取。

~/.bashrc

现在开发环境下,不需要登陆的 shell 是比较常见的,在这种 shell

中,用户不需要提供用户名和密码。此时 bash 会读取 ~/.bashrc 配置文件。

~/.bash_logout

Command line

In case you're curious, this is how you would copy a file under WSL to your Windows clipboard:

cat report.txt | clip.exe