Linux命令使用与脚本编写简介

Linux命令

常用命令

cd

ls

awk

sed

ps

df

fdisk

wc

find

grep/egrep

top

vi/vim

diff/vimdiff

man

查看内置帮助手册,不仅可以查看命令手册,还有系统调用、库函数、异常码、宏等等信息。

1
2
3
4
5
6
7
8
# 学习如何RTFM
$ man man
# 学习如何使用库函数
$ man 3 getopt
# 检索含有关键词xxx的命令
$ man -k xxx
$ man readline
$ man bash

xargs

strace

system call trace, 记录程序运行过程中的系统调用信息

netstat

ip

ifconfig

ssh

telnet

sort

history

!n再次执行编号n命令

!xxx再次执行以xxx开头的最近一条命令

yes

不断重复输出y

watch

在前台定时执行命令

1
2
3
4
5
6
$ watch -t -n 1 "echo -n '第六期一生一芯 | 周六 15:00~17:00 | '; \
date; echo '课程主页 https://ysyx.oscc.cc/docs/'"
第六期一生一芯 | 周六 15:00~17:00 | Thu Apr 4 16:58:59 CST 2024
课程主页 https://ysyx.oscc.cc/docs/


crontab

在后台定时执行命令,需要编写对应的配置文件

timeout

执行特定时间,返回超时或命令自身的返回值

  • 0:命令成功执行并完成。
  • 124:命令因超时而终止。
  • 其他:命令执行失败
1
$ timeout 6 mkdir -p /mnt/dev0

脚本编写

细节介绍参考man bash

基本语法

简介

脚本的本质就是将众多Linux小工具按照一定的逻辑顺序依次执行处理,脚本文件内容就是这些命令的集合。

程序运行时都会打开3个文件

  • 0号文件,标准输入
  • 1号文件,标准输出
  • 2号文件,标准错误输出

可以通过lsof -p <PID>查看进程打开的文件。

>重定向标准输出,>>追加方式重定向标准输出,2>&1将标准错误重定向到标准输出。

内置变量有

  • $0 $1 ... $n:脚本名称(有时会包含相对或绝对路径)、第1个参数……第n个参数
  • $?:最后一条命令或函数的返回值
  • $@:传递$0之外的所有参数,可以用数组保存其值:ALL_ARGS=("$@")
  • $#:传递给脚本或函数的参数个数

内置命令

shift

基本格式:shift [n]

将参数左移n位,默认值为1

变量用法

基本用法

使用示例

1
2
3
4
# 变量赋值
var="/root/project/abc"
# 变量使用
echo $var ${var}

变量展开

又名shell参数展开,基本格式

1
2
3
4
${变量##模式}
${变量#模式}
${变量%%模式}
${变量%模式}

模式支持的符号:

  • * 匹配任意字符串
  • ? 匹配任意单个字符
  • [...] 匹配字符集,比如:范围[0-9a-z],取反[!abc][^abc]
  • \ 匹配转义字符,比如:*

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ var="/root/project/abc"
# 从左开始,最小匹配模式删除匹配字符串
$ echo ${var#*/}
root/project/abc

# 从左开始,最大匹配模式删除匹配字符串
$ echo ${var##*/}
abc

# 从右开始,最小匹配模式删除匹配字符串
$ echo ${var%/*}
/root/project
# 从右开始,最大匹配模式删除匹配字符串
$ echo ${var%%/*}

交互界面

基本操作

  • Tab键自动补全
  • 上下方向键遍历历史命令

任务管理

  • Ctrl+Z最小化,或运行时命令末尾添加&(但用户退出后后台任务也会退出,可以使用nohup命令避免)
  • jobs任务栏
  • bg后台执行任务,将指定任务2切换到后台执行bg %2
  • fg前台执行任务,将指定任务2切换到前台执行fg %2

shell可以通过快捷键操作光标快速移动,更多快捷键可以阅读man readlineCommands for Moving部分

  • Ctrl+B光标前移一个字符
  • Ctrl+F光标后移一个字符
  • Ctrl+A光标移到首字符处
  • Ctrl+E光标移到首字符处

基本单元

shell都是基于文本进行处理,其中只有数字字符串在特定场景可以进行数学运算。

通配符

  • *任意长度的字符串
  • ?任意一个字符
  • [xxx]集合中任意一个字符

示例

1
2
$ echo Hello-{a,bb,ccc}-{1,2}!
Hello-a-1! Hello-a-2! Hello-bb-1! Hello-bb-2! Hello-ccc-1! Hello-ccc-2!

数组

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 创建一个数组
array=()
declare -a array

# 添加元素
array+=("item0")
array+=("item1")
array+=("item2")

# 遍历一个数组
for item in $array; do echo item is $item; done
for i in {1..${#array[@]}}; do item=${array[$i]}; echo item is $item; done
for item in ${array[@]}; do echo item is $item; done

# 删除指定元素
unset 'array[1]' # 删除item0,但是索引依然保留
# 重新创建一个新数组,通过过滤方式
new_array=()
for item in ${array[@]}; do
if [ $item != "item0" ]; then
new_array+=("$item")
fi
done

# 删除整个数组
unset array
array=() # 清空整个数组

判断逻辑

if

1
$ if mkdir -p /mnt/dev0; then echo ok; else echo error; fi

命令执行成功则打印ok,否则打印失败

case

循环逻辑

while

1
2
3
$ while [[ `seq 1 10 | shuf | head -n 1` != "1" ]]; do echo "retry"; done
retry
retry

for

捕获信号

trap 命令用于捕获和处理信号或错误。当特定信号发生时,trap 可以执行指定的命令。trap 可以捕获多种信号,包括系统信号和错误。

一些常见的信号量包括:

  • SIGINT (2): 中断信号,通常由 Ctrl+C 触发。
  • SIGTERM (15): 终止信号,通常由 kill 命令发送,用于请求进程终止。
  • SIGKILL (9): 强制终止信号,无法被捕获或忽略,通常用于强制停止进程。
  • SIGQUIT (3): 退出信号,通常由 Ctrl+ 触发,用于生成 core dump。
  • SIGSTOP (19): 停止信号,无法被捕获或忽略,通常用于挂起进程。
  • SIGCONT (18): 恢复信号,用于恢复一个被 SIGSTOP 停止的进程。
  • SIGHUP (1): 挂起信号,通常是终端关闭时发送的。
  • SIGUSR1SIGUSR2: 用户自定义信号,可以用来传递特定信息。
  • SIGSEGV (11): 段错误信号,通常在程序访问非法内存时触发。
  • SIGPIPE (13): 管道破裂信号,通常当向一个没有读取者的管道写数据时触发。

常见的错误有:

  • EXIT:捕获脚本或命令退出时的状态(返回码)。例如,你可以捕获脚本退出时的状态码,或者通过 trap 在脚本退出时执行清理工作。
  • ERR:捕获任何命令的非零退出状态(发生错误时触发)。通过 trap 'command' ERR,你可以在发生错误时执行指定的命令。
1
2
3
4
5
6
7
8
#!/bin/bash

exit_handler() {
# 具体处理逻辑
}

trap exit_handler SIGINT SIGTERM EXIT ERR

输入输出

经典示例

输入参数解析

1
2
3
4
5
6
输入的参数可以包含以下几种情况的任意组合,<xxx>表示参数后必须跟对应的值:
-n <num>
--number <num>
-v
--version
-h

case手动解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

# 手动解析参数
while [ $# -gt 0 ]; do
case "$1" in
-n|--number)
# 确保后面有值
if [ -n "$2" ] && [[ "$2" != -* ]]; then
number="$2"
shift 2
else
echo "错误: -n 或 --number 需要一个参数"
exit 1
fi
;;
-v|--version) show_version=true; shift; ;;
-h|--help) show_help=true; shift; ;;
*)
echo "忽略非选项参数: $1"
shift
;;
esac
done

自制CPU主频监视器

1
$ watch -n 1 "cat /proc/cpuinfo | grep MHz | awk '{print \$1 NR \$3 \$4 \$2}'"

打包特定文件并上传到远端

1
$ find . -name "*.pdf" | xargs tar cj | ssh yzh@192.168.1.1 'cd ysyx; > pdf.tar.bz2'

统计工具类型分布

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ echo $PATH | tr -t : '\n' | xargs -I{} find {} -maxdepth 1 -type f -executable | \
xargs file -b -e elf | sort | uniq -c | sort -nr

835 ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV)
129 Perl script text executable
113 POSIX shell script, ASCII text executable
34 Python script, ASCII text executable
24 ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux)
20 Bourne-Again shell script, ASCII text executable
15 setuid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV)
12 setgid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV)
10 ELF 64-bit LSB executable, x86-64, version 1 (SYSV)
9 POSIX shell script, Unicode text, UTF-8 text executable
3 ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux)
2 Python script, Unicode text, UTF-8 text executable
2 PHP script, ASCII text executable
1 setuid, setgid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV)
1 Python script, ISO-8859 text executable
1 POSIX shell script, ASCII text executable, with very long lines (459)
1 PHP phar archive with SHA1 signature
1 Paul Falstad's zsh script, ASCII text executable
1 JavaScript source, ASCII text