# 使用
echo $变量名
# 或
echo ${变量名}
# 设置(等号两边不能加空格)
变量名=值
# 取消
unset 变量名
`命令`
或 $(命令)
(建议)${变量名}
(建议)或 "$变量名"
ding@ding-server:~$ echo "The $(uname) core version is: $(uname -r)"
The Linux core version is: 5.4.0-109-generic
ding@ding-server:~$ echo 'The $(uname) core version is: $(uname -r)'
The $(uname) core version is: $(uname -r)
ding@ding-server:~$ name=Ding\ Junyao
ding@ding-server:~$ echo $name
Ding Junyao
ding@ding-server:~$ name=${name}\'s\ name
ding@ding-server:~$ echo $name
Ding Junyao's name
ding@ding-server:~$ name='This is '${name}
ding@ding-server:~$ echo $name
This is Ding Junyao's name
环境变量的作用范围为当前环境。
通过前面的流程设置的变量的作用范围为当前进程,在子进程中无法使用。如果需要在子进程中使用,需要设置为环境变量:
export 变量名
直接定义环境变量:
export 变量名=值
例:
# 在父进程
ding@ding-server:~$ echo $name
This is Ding Junyao's name
ding@ding-server:~$ bash
# 至此离开父进程,进入子进程 1
ding@ding-server:~$ echo $name
ding@ding-server:~$ exit
exit
# 至此离开子进程 1,到父进程
ding@ding-server:~$ echo $name
This is Ding Junyao's name
ding@ding-server:~$ export name
ding@ding-server:~$ bash
# 至此离开父进程,进入子进程 2
ding@ding-server:~$ echo $name
This is Ding Junyao's name
经此前 export
配置,这时候的变量仅在当前登录终端有效。如果想要永久有效,需要更改配置文件,在其中添加设置变量的指令。
Bash 的 Login Shell 的配置文件结构如下图,需按需更改对应的配置文件。这些配置文件均为 Shell 脚本。
配置后,下次登录时即生效。如果想立即生效,执行:
source 配置文件路径
# 或
. 配置文件路径
ding@ding-server:~$ env
SHELL=/bin/bash
JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/
PWD=/home/foxconn
LOGNAME=foxconn
HOME=/home/foxconn
LANG=en_US.UTF-8
LESSOPEN=| /usr/bin/lesspipe %s
USER=foxconn
PATH=/usr/lib/jvm/java-11-openjdk-amd64//bin:/usr/lib/jvm/java-11-openjdk-amd64//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
SSH_TTY=/dev/pts/0
_=/usr/bin/env
...
set
PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
PS2='> '
PS4='+ '
...
?
- 上一个命令的返回值ding@ding-server:~$ ls
0507 a.txt
...
foxconn@hcm0153:~$ echo $?
0
foxconn@hcm0153:~$ ls 11.txt
ls: cannot access '11.txt': No such file or directory
foxconn@hcm0153:~$ echo $?
2
foxconn@hcm0153:~$ echo $?
0
一般返回值为 0
表示命令执行成功,非 0
表示执行失败
# 设置别名(虽然可以用双引号包裹,但还是建议用单引号)
alias 别名='命令'
# 查看目前使用中的别名
alias
# 删除别名
unalias 别名
别名的作用范围和变量一样,如果想永久保存别名,同样需要更改配置文件。
alias rm='rm -i'
ding@ding-server:~$ alias
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
alias cd='rm -rf'
多个命令之间用 ;
连接,表示无条件分步执行。
&&
和 ||
有“且”和“或”的意义。
# 如果目录不存在则新建
ls 目录路径 || mkdir -p 目录路径
# 软件包安装成功才运行程序
sudo apt install 软件包 && 程序
# 尝试新建文件(文件所在目录可能不存在)
ls 目录路径 || mkdir -p 目录路径 && touch 文件路径
判断文件是否存在,如存在打印 ”exist
”,否则打印 ”not exist
”。
答案是:
ls 文件 && echo "exist" || echo "not exist"
如果写成了
ls 文件 || echo "not exist" && echo "exist"
则如果文件不存在:
结果如下:
ls: cannot access '文件': No such file or directory
not exist
exist
命令1 && 命令2 || 命令3
其中命令 2、3 会使用肯定成功的命令。
等价于:
流程图如下:
如果命令 1 返回值为 0
(成功):
如果命令 1 返回值非 0
(失败):
一般来说是将内容输出到文件。
命令 > 路径
命令 >> 路径
>
和 >>
的差别:如果文件已存在,>
会清空原有内容,>>
会在原有内容之后累加。
例:
ding@ding-server:~$ ls -al /
total 4194436
drwxr-xr-x 21 root root 4096 Apr 13 15:25 .
drwxr-xr-x 21 root root 4096 Apr 13 15:25 ..
lrwxrwxrwx 1 root root 7 Feb 23 16:49 bin -> usr/bin
...
ding@ding-server:~$ ls -al / > test.txt
ding@ding-server:~$ cat test.txt
total 4194436
drwxr-xr-x 21 root root 4096 Apr 13 15:25 .
drwxr-xr-x 21 root root 4096 Apr 13 15:25 ..
lrwxrwxrwx 1 root root 7 Feb 23 16:49 bin -> usr/bin
...
ding@ding-server:~$ ls -al / >> test.txt
ding@ding-server:~$ cat test.txt
total 4194436
drwxr-xr-x 21 root root 4096 Apr 13 15:25 .
drwxr-xr-x 21 root root 4096 Apr 13 15:25 ..
lrwxrwxrwx 1 root root 7 Feb 23 16:49 bin -> usr/bin
...
total 4194436
drwxr-xr-x 21 root root 4096 Apr 13 15:25 .
drwxr-xr-x 21 root root 4096 Apr 13 15:25 ..
lrwxrwxrwx 1 root root 7 Feb 23 16:49 bin -> usr/bin
...
...
重定向到设备时,一般不要用累加符号。
传到另一个终端:
传到黑洞设备:
命令 > /dev/null
命令 2> 路径
命令 2>> 路径
# 将标准输出和标准错误输出放到不同的地方(> 可以按需换成 >>)
命令 > 标准输出路径 2> 标准错误输出路径
# 将标准输出和标准错误输出放到相同的地方,不能使用上面的方法,会导致交叉写入,造成次序混乱;用下面的方法:
命令 > 路径 2>&1 # 较常用;注意顺序
# 或
命令 &> 路径
例:
将某内容传入命令的标准输入:
命令 < 路径
对命令的标准输入传入一段内容,自定义结束符号(默认为 Ctrl + D):
命令 << 结束符号
> 内容
> 内容...
> 结束符号
前面的符号是在终端输入时自动添加的,不是输入内容;如果写脚本,直接写内容和结束符号就行了。
例:
命令1 | 命令2
命令1 | 命令2 | 命令3
...
当需要传递标准错误输出时,可以利用重定向。
命令1 2>&1 | 命令2
命令1 2>&1 > /dev/null | 命令2
# 注意顺序
例:
grep
- 输出包含要找的文字所在的行grep [选项] 要找的文字 文件
... | grep [选项] 要找的文字
# 支持标准输入的命令都有类似的形式,后续如无特殊情况不再写出
选项:
-c
:输出符合条件的行的数量-i
:忽略大小写-n
:在符合条件的行前输出行号-v
:输出不符合条件的行--color=auto
:高亮显示要找的文本(一般会使用别名默认启用该功能)cut
- 截取每一行的特定文本# 在以某字符为分隔的数据中,取出某段文本
cut -d '分隔字符' -f 要取出的段的序号 文件
# 以字符为单位取出文本
cut -c 字符序号区间 文件
序号从 1 开始。
ding@ding-server:~$ echo $PATH
/home/foxconn/.local/bin:/home/foxconn/.local/bin:/usr/lib/jvm/java-11-openjdk-amd64//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
ding@ding-server:~$ echo $PATH | cut -d ':' -f 2,4,5
/home/foxconn/.local/bin:/usr/local/sbin:/usr/local/bin
ding@ding-server:~$ echo $PATH | cut -d ':' -f 2
/home/foxconn/.local/bin
ding@ding-server:~$ echo $PATH | cut -d ':' -f 2-4
/home/foxconn/.local/bin:/usr/lib/jvm/java-11-openjdk-amd64//bin:/usr/local/sbin
ding@ding-server:~$ echo $PATH | cut -d ':' -f 5-
/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
ding@ding-server:~$ echo $PATH | cut -d ':' -f -3
/home/foxconn/.local/bin:/home/foxconn/.local/bin:/usr/lib/jvm/java-11-openjdk-amd64//bin
ding@ding-server:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
ding@ding-server:~$ cut -d ':' -f 1,6 /etc/passwd
root:/root
daemon:/usr/sbin
bin:/bin
...
ding@ding-server:~$ export
declare -x CLASSPATH=".:/usr/lib/jvm/java-11-openjdk-amd64//lib/dt.jar:/usr/lib/jvm/java-11-openjdk-amd64//lib/tools.jar"
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
...
ding@ding-server:~$ export | cut -c 12-
CLASSPATH=".:/usr/lib/jvm/java-11-openjdk-amd64//lib/dt.jar:/usr/lib/jvm/java-11-openjdk-amd64//lib/tools.jar"
DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
...
如果列之间用了多个空格,则不能使用该命令去提取。
ding@ding-server:~$ last
foxconn pts/3 10.94.5.157 Tue May 17 14:11 still logged in
foxconn pts/2 10.94.5.157 Tue May 17 10:42 still logged in
foxconn pts/4 10.94.0.112 Tue May 17 09:07 - 10:10 (01:03)
...
ding@ding-server:~$ last | cut -d ' ' -f 1
foxconn
foxconn
foxconn
foxconn
ding@ding-server:~$ last | cut -d ' ' -f 2
...
sort
- 排序sort [选项] 文件
选项:
-f
:忽略大小写-b
:忽略最前面的空格-M
:以月份名称(JAN
、DEC
…)排序-n
:使用纯数字排序(默认是以文字形式排序的)-r
:反向排序-u
:去重-t 分隔符号
:指定分隔符号(默认是 Tab)-k 段序号或区间
:以哪个 / 哪些段排序(用法和 cut
一样)-c
:检查文件是否有序例:
ding@ding-server:~$ sort /etc/passwd
admin:x:1002:1002:admin,,,:/home/admin:/bin/bash
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
...
ding@ding-server:~$ sort -t ':' -k 3 /etc/passwd
root:x:0:0:root:/root:/bin/bash
foxconn:x:1000:1000:foxconn:/home/foxconn:/bin/bash
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
J6100354:x:1001:1001::/home/J6100354:/bin/sh
...
ding@ding-server:~$ sort -t ':' -k 3 -n /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...
ding@ding-server:~$ sort -t ':' -k 3 -n -r /etc/passwd
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
admin:x:1002:1002:admin,,,:/home/admin:/bin/bash
...
uniq
- 去重uniq [选项] 文件
只会在连续的范围内去重。
选项:
-i
:忽略大小写-c
:计数-u
:仅输出无重复的行例:
ding@ding-server:~$ last | cut -d ' ' -f 1 | uniq
foxconn
reboot
foxconn
reboot
foxconn
...
ding@ding-server:~$ last | cut -d ' ' -f 1 | sort | uniq
foxconn
reboot
wtmp
ding@ding-server:~$ last | cut -d ' ' -f 1 | sort | uniq -c
1
198 foxconn
12 reboot
1 wtmp
wc
- 字数统计wc [选项] 文件或目录
如果有多个文件,会在最下方列出总和。
选项:
-l
:多少行-w
:多少词(以英文的方式判定)-c
:多少字节-m
:多少字符(换行符也包含在内)-L
:列出最长一行的字符长度例:
ding@ding-server:~$ cat wctest.txt
This is some text.
这是一段文本示例。
123456
ding@ding-server:~$ wc wctest.txt
3 6 54 wctest.txt
ding@ding-server:~$ wc -m wctest.txt
36 wctest.txt
ding@ding-server:~$ last | cut -d ' ' -f 1 | grep [a-zA-Z] | grep -v 'wtmp' | grep -v 'reboot' | grep -v 'unknown' | sort | uniq | wc -l # 显示登录过的用户数量
2
tee
- 双向重定向tee [选项] 文件
选项:
-a
:追加常用在两个命令之间:
... | tee [选项] 文件 | ...
例:
ding@ding-server:~$ last | tee last.txt | cut -d ' ' -f 1 | sort | uniq
foxconn
reboot
wtmp
ding@ding-server:~$ cat last.txt
foxconn pts/3 10.94.5.157 Tue May 17 14:11 still logged in
foxconn pts/2 10.94.5.157 Tue May 17 10:42 still logged in
foxconn pts/4 10.94.0.112 Tue May 17 09:07 - 10:10 (01:03)
...
执行 history
可以查看最近的命令。如果限定查看最近的若干条命令,可以加上数字作为参数。
Bash 记录历史命令时,会把命令里面的字符记录进去,所以一般不要在命令中写密码等敏感信息。
ding@ding-server:~$ history
1216 sudo docker-compose -f docker-compose-mysql.yml down
...
2213 sudo whoami
2214 whoami
2215 history
执行历史命令时,使用 !
加上一些参数,例子见下。
执行时,首先会列出将要执行的命令。
ding@ding-server:~$ !2214 # 执行历史记录中的第 2214 条命令
whoami
ding
ding@ding-server:~$ !sudo # 执行开头为 sudo 的最近的命令
sudo whoami
root
ding@ding-server:~$ !2214
whoami
ding
ding@ding-server:~$ !! # 执行最近一条命令
whoami
ding
ding@ding-server:~$ sudo !!
sudo whoami
root
# 立即将目前的数据写入历史记录文件(默认为 ~/.bash_history)
history -w
# 查看历史记录保留的最大条数
echo ${HISTSIZE}
# 清除当前用户的历史记录
history -c
Shell(壳层、壳程序) 是为用户提供用户界面的软件。能够操作应用程序。相对于内核(Kernel)而言。
有命令行和图形界面之分:
以下提供了两个系统中两种 Shell 的操作,操作分别为:
chsh -l
查看)sh
被指定为哪个 Shell# CentOS Linux release 7.9.2009, fish
# 查看当前 Shell
ding@ding-server ~> echo $SHELL
/usr/bin/fish
# 查看可用的 Login Shell
ding@ding-server ~> cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
/bin/zsh
/usr/bin/fish
# 查看 sh 被指定为哪个 Shell
ding@ding-server ~> ll /bin/sh
lrwxrwxrwx. 1 root root 4 Jul 15 2021 /bin/sh -> bash*
# Ubuntu 20.04 LTS, bash
# 查看当前 Shell
ding@ding-server:~$ echo $SHELL
/bin/bash
# 查看可用的 Login Shell
ding@ding-server:~$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash
/usr/bin/tmux
/usr/bin/screen
# 查看 sh 被指定为哪个 Shell
ding@ding-server:~$ ll /bin/sh
lrwxrwxrwx 1 root root 4 Feb 23 16:50 /bin/sh -> dash*
通常的 Shell 脚本,默认会以 sh
执行。
传统意义上的 sh 指 Bourne Shell,由 AT&T 公司的 Steve Bourne 开发,是 UNIX 系统上的标准 Shell。
Linux 上一般会指向 bash(Bourne Again Shell),属于 GNU 计划的一部分。
但 Debian 发行版中指向的是 dash(Debian Almquist Shell),由 ash(Almquist Shell ,BSD 等上的预装 Shell) 发展而来,更为小巧。
dash 对一些命令的支持与 bash 不同(如 echo
命令不支持 -e
选项),故写、执行脚本时要注意。
内部命令指 Shell 程序自带的命令;外部命令指其他程序提供的命令。
内部命令的列表可以通过 enable
查看。
判断命令属于哪种,可以用 type [-a]
命令
内部命令与外部命令名称相同时,优先执行内部命令(如 pwd
)。
各 Shell“对命令的支持不同”,一般指的是内部命令。
有一些优化(如自动补全、高亮),适合用于个人工作。可以参考:
通过第三方插件,能够实现更好的效果。
但配置文件、脚本语法等和 bash 有不可忽视的差别,尤其是配置文件。
macOS 的终端默认使用 zsh。
Linux 中如果有 csh( C shell ),一般指向 tcsh(Tenex C shell),有补全等功能。
bash 的一些功能(如历史记录、别名)受其影响。
与 bash 的语法和配置文件差别很大。
现在很少用。
nologin
打印账号不可用的信息(可通过 /etc/nologin.txt
配置),返回非零值。
用于不可登录的用户:给其配置默认 Shell 为它,使其不可通过 Shell 登录。
ding@ding-server:~$ /sbin/nologin
This account is currently not available.
ding@ding-server:~$ echo $?
1
ding@ding-server:~$ cat /etc/passwd
...
games:x:5:60:games:/usr/games:/usr/sbin/nologin
...
ding@ding-server:~$ sudo su - games
This account is currently not available.
ding@ding-server:~$
是受限制的 bash,严格意义上来说是 bash 的特殊功能,相当于 bash -r
。
在 Debian 系发行版中,rbash
指向 bash
(但实际效果不一样);如果没有,可以创建符号链接。
可以用作中转服务器,或者仅使用 ssh 来访问网页等等。
受限的情况:https://www.howtoing.com/rbash-a-restricted-bash-shell-explained-with-practical-examples/
但不绝对安全,可以通过运行 bash
等方式脱离控制。
创建会话:
screen
screen 命令
离开会话:按 Ctrl + A,再按 D
查看会话:
ding@ding-server:~$ screen -ls
There is a screen on:
1524444.pts-1.hcm0153 (05/19/2022 03:02:27 PM) (Detached)
1 Socket in /run/screen/S-foxconn.
重进上面的会话:
screen -r 152444