Linux技术栈 —— 运维基础
〇、基础知识
0.1 安装虚拟机
首先,既然接触了Linux,就永远不要怕把机器折腾坏,装一个用来测试的Linux虚拟机,就用来玩这些危险命令,或者是你觉得可能把机器搞坏、搞的别扭的命令,不要担心重装系统,多重装几遍到时候你真遇到问题反而是好事,要不怕操作Linux的任何命令,就是干!
参考文章 |
---|
[1] CentOS 7 5 Installation with LVM Partitioning |
0.2 Linux目录详解
参考文章 |
---|
《Linux系统中目录的内容详解—bin、dev、etc、home、lib、opt、usr、var》 |
一、进程管理
1.1 查找特定name进程并杀死
# 定义颜色
RED='\033[0;31m' # 红色
NC='\033[0m' # 没有颜色(重置)
proc_name="xxxx"
proc_id=$(ps -ef | grep ${proc_name} | grep -v grep | awk '{print $2}')
# 注意,这里的过滤条件还是比较粗糙的,为避免误杀,请给proc_name的命名以严格限制,或者多加几道grep过滤条件
# 如: ps -ef | grep ${proc_name} | grep -v grep | grep .. | grep .. | [grep ..]
if [ -n "${proc_id}" ]; then
echo "找到进程名为${proc_name}的进程,其PID为:${proc_id}"
kill -9 ${proc_id}
else
echo -e "${RED}未找到名为${proc_name}的进程!${NC}"
fi
对上面这几行命令做下解释
(1)ps -ef | grep ${proc_name}
意思为找到所有 名字包含了proc_name
的进程
(2)grep -v grep
即过滤掉grep查找进程本身
(3)awk '{print $2}'
提取找到的进程行记录中第二列的参数,也就是flask的进程号,awk
的一个内置函数,awk '{print $2}' 文件名
会读取文件名指定的文件,并输出每一行的第二个字段的值。
(4)if [ -n xx]
见Shell scripting: -z and -n options with if,-n
的意思是用来判断字符串非空的
然后,我们还可以对这段脚本做一下升级,用一个名字数组,以后就可以批量化查杀进程了。
#!/bin/bash
# 定义颜色
RED='\033[0;31m' # 红色
NC='\033[0m' # 没有颜色(重置)
GREEN='\033[0;32m' # 绿色
# 定义包含进程名称的数组或读取自文件
# 方法 1: 使用数组
process_names=("process_name_1" "process_name_2" "process_name_3")
# 方法 2: 从文件读取(每行一个进程名称)
# process_names=($(cat process_list.txt))
# 遍历每个进程名称
for proc_name in "${process_names[@]}"; do
echo "正在查找进程名为 ${proc_name} 的进程..."
# 查找进程 ID
proc_ids=$(ps -ef | grep "${proc_name}" | grep -v grep | awk '{print $2}')
# 检查是否找到进程
if [ -n "${proc_ids}" ]; then
echo -e "${GREEN}找到进程名为 ${proc_name} 的进程,其PID为:${proc_ids}${NC}"
# 遍历找到的进程 ID 并查杀
for pid in ${proc_ids}; do
echo "正在杀掉进程 PID: ${pid}..."
kill -9 ${pid}
if [ $? -eq 0 ]; then
echo -e "${GREEN}成功杀掉进程 PID: ${pid}${NC}"
else
echo -e "${RED}无法杀掉进程 PID: ${pid},请检查权限或进程状态。${NC}"
fi
done
else
echo -e "${RED}未找到名为 ${proc_name} 的进程!${NC}"
fi
done
参考文章 |
---|
《Linux下如何通过一行命令查找并杀掉进程》 |
1.2 查找特定port的进程并杀死
1.3 jar包启动脚本
#!/bin/bash
JAR_NAMES=("yourApp.jar")
PID_FILES=("yourApp.pid")
LOG_FILES=("yourApp.log")
start() {
local jar_to_start=$1
for i in "${!JAR_NAMES[@]}"; do
JAR_NAME="${JAR_NAMES[$i]}"
PID_FILE="${PID_FILES[$i]}"
LOG_FILE="${LOG_FILES[$i]}"
if [ -n "$jar_to_start" ] && [ "$jar_to_start" != "$JAR_NAME" ]; then
continue
fi
if [ -f "$PID_FILE" ]; then
echo "应用程序 $JAR_NAME 已在运行,PID: $(cat $PID_FILE)"
else
echo "启动应用程序 $JAR_NAME..."
nohup java -jar "$JAR_NAME" > "$LOG_FILE" &
echo $! > "$PID_FILE"
echo "应用程序 $JAR_NAME 已启动,PID: $(cat $PID_FILE)"
fi
done
}
stop() {
local jar_to_stop=$1
for i in "${!JAR_NAMES[@]}"; do
JAR_NAME="${JAR_NAMES[$i]}"
PID_FILE="${PID_FILES[$i]}"
if [ -n "$jar_to_stop" ] && [ "$jar_to_stop" != "$JAR_NAME" ]; then
continue
fi
if [ -f "$PID_FILE" ]; then
echo "停止应用程序 $JAR_NAME,PID: $(cat $PID_FILE)..."
kill $(cat "$PID_FILE")
rm -f "$PID_FILE"
echo "应用程序 $JAR_NAME 已停止"
else
echo "没有找到运行中的应用程序 $JAR_NAME"
fi
done
}
restart() {
local jar_to_restart=$1
stop "$jar_to_restart"
start "$jar_to_restart"
}
status() {
local jar_to_status=$1
for i in "${!JAR_NAMES[@]}"; do
JAR_NAME="${JAR_NAMES[$i]}"
PID_FILE="${PID_FILES[$i]}"
if [ -n "$jar_to_status" ] && [ "$jar_to_status" != "$JAR_NAME" ]; then
continue
fi
if [ -f "$PID_FILE" ]; then
echo "应用程序 $JAR_NAME 正在运行,PID: $(cat $PID_FILE)"
else
echo "应用程序 $JAR_NAME 未运行"
fi
done
}
case "$1" in
start)
start "$2"
;;
stop)
stop "$2"
;;
restart)
restart "$2"
;;
status)
status "$2"
;;
*)
echo "用法: $0 {start|stop|restart|status} [jar_name]"
esac
exit 0
1.4 查看Nvidia GPU显存情况
#!/bin/bash
# 检查 nvidia-smi 是否可用
if ! command -v nvidia-smi &> /dev/null; then
echo "nvidia-smi 命令未找到,请确保已安装 NVIDIA 驱动程序和工具。"
exit 1
fi
# 函数:将 MiB 转换为 GB(保留前导零和两位小数)
convert_mib_to_gb() {
printf "%.2f" "$(echo "scale=2; $1 / 1024" | bc)"
}
# 获取 GPU 数量
gpu_count=$(nvidia-smi --query-gpu=name --format=csv,noheader | wc -l)
# 遍历每个 GPU 获取显存信息和运行的进程
for ((i=0; i<gpu_count; i++)); do
gpu_name=$(nvidia-smi --query-gpu=name --format=csv,noheader,nounits -i $i)
memory_total_mib=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits -i $i)
memory_used_mib=$(nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits -i $i)
memory_free_mib=$(nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits -i $i)
memory_total_gb=$(convert_mib_to_gb $memory_total_mib)
memory_used_gb=$(convert_mib_to_gb $memory_used_mib)
memory_free_gb=$(convert_mib_to_gb $memory_free_mib)
echo "GPU $i: $gpu_name"
echo " 总显存: ${memory_total_gb} GB"
echo " 已用显存: ${memory_used_gb} GB"
echo " 空闲显存: ${memory_free_gb} GB"
echo " 正在运行的进程及其显存使用情况:"
# 获取正在使用该 GPU 的进程
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv,noheader,nounits -i $i | while IFS=',' read -r pid process_name used_memory_mib; do
if [ -n "$pid" ]; then
used_memory_gb=$(convert_mib_to_gb $used_memory_mib)
# 显示进程信息
echo " PID: ${pid}, 进程名: ${process_name}, 使用显存: ${used_memory_gb} GB"
fi
done
echo ""
done
也可以安装nvitop
进行查看。
1.5 会话与窗口解绑之tmux
一个典型的例子就是,SSH 登录远程计算机,打开一个远程窗口执行命令。这时,网络突然断线,再次登录的时候,是找不回上一次执行的命令的。因为上一次 SSH 会话已经终止了,里面的进程也随之消失了。
为了解决这个问题,会话与窗口可以解绑:窗口关闭时,会话并不终止,而是继续运行,等到以后需要的时候,再让会话"绑定"其他窗口。
1.4 参考视频或文章链接 |
---|
[1] Tmux 使用教程 |
二、磁盘管理
2.1 磁盘挂载
2.2 磁盘空间分配与扩容
如果是单磁盘,可以偷个懒,在VMware中直接扩展磁盘容量,然后重新分配大小即可
2.2 参考视频或文章链接 |
---|
[1] 《VMware上的linux虚拟机磁盘空间满了,如何扩充磁盘空间?》—— 优快云 |
[2] 《为虚拟机指定磁盘容量》—— VMware DOC |
[3] 《VMware虚拟机扩展磁盘空间》—— 优快云 |
[4] 《增加 VM虚拟机硬盘容量》—— 优快云 |
[5] Ubuntu-Server服务器版本重点查看,可快速解决 《ubuntu 里根文件系统的扩容,/dev/ubuntu-vg/ubuntu-lv 文件系统扩充到整个分区》—— 优快云 |
[6] LVM Extending Fails |
[7] Resizing Ubuntu partition with resize2fs |
[8] Linux分区工具:Fdisk与Parted以及GParted |
[9] 笔者实战,可以参考 Linux技术栈 —— 记一次Ubuntu系统 / 目录磁盘扩容 |
2.3 parted对Linux进行磁盘扩容
2.3 参考视频或文章链接 |
---|
[1] 《使用parted命令为磁盘扩容》—— 优快云 |
[2] 《linux下无损扩容分区方法》—— 知乎 |
三、文件管理
3.1 删除文件
操作方式 | 评价 |
---|---|
rm -rf /path/to/xxxfolder[file] | -r 是recursively递归删除,-f 是forcely强制删除,一旦在root权限下执行,可能造成不可逆的损失 |
trash filename | 先使用sudo apt install trash-cli 安装该工具,该命令删除的文件会在垃圾箱中,即~/.local/share/Trash/files 目录下,确认要清空垃圾箱,请使用trash-empty |
mv filename ~/.local/share/Trash/files | 用mv 命令,把文件移动至垃圾箱中,使用find ~/.local/share/Trash/* -delete 命令清空,这个命令不用安装trash-cli |
总结:其实Linux中,删除文件或文件夹的命令常用的还是rm
,但是一旦获取了root用户权限,这个命令就比较危险了,要安全方向的删除文件的话,考虑trash
或mv
,其实trash
底层彻底清空文件也是用rm
,但是它封装好了,就比较安全。另外,选中文件Shift + Delete
是永久删除。并且root
用户如果没有执行过trash
命令的话,是没有对应的Trash
文件夹的,那root
用户能执行trash
吗?答案是可以,trash
会自动创建。
参考视频或文章链接 |
---|
《你不知道Linux的10个最危险的命令》 |
How to Empty the Trash in Linux CLI - Baeldung Linux |
How to Delete a File in Linux (5 Methods) |
3.2 查找指定内容的文件
你想找到这样的一份文件,这份文件的某一行出现了你感兴趣的数据,那么在linux中如何完成这件事?
# 1.搜索多个文件并显示行号
grep -rn "example" *.txt
# 2.递归搜索当前目录中所有文件
grep -rn "example" .
# 3.正则表达式搜索
grep -rnE "exa(mple|ct)" /path/to/directory
3.3 解压文件到指定目录
mkdir -p /your_path/demo_dir/ && tar -zxvf demo.tar.gz -C /your_path/demo_dir/
四、Shell编程
4.1 脚本接受多个参数并选择执行
稍微有点项目经验的话,你可能运行过类似于startApplication.sh start
或startApplication.sh restart
这样的命令,可以根据参数的不同,决定是启动还是重启,那么这样的脚本实现原理是什么?
#!/bin/bash
#test.sh
# 获取参数
param1=$1
param2=$2
# 使用case语句判断参数值并执行相应命令
case $param1 in
"option1")
echo "执行命令1"
;; # case语句中的结束符,表示当前条件分支已经处理完毕。
"option2")
echo "执行命令2"
;;
*)
echo "未知参数,请输入正确的选项"
;;
esac # case语句的结束。
echo "第2个参数为:${param2}"
赋予文件可执行权限,你会看到以下效果,因此你可以在此基础上继续延伸,开发出你想要的脚本文件功能。
# ./test.sh option1 args2
执行命令1
第2个参数为:args2
# ./test.sh option2 args2
执行命令2
第2个参数为:args2
五、系统配置
5.1 配置网络代理proxy
基本的方法是配置HTTP_PROXY
与HTTPS_PROXY
# /etc/profile 或 ~/.bashrc 中添加
export HTTP_PROXY="http://{your_ip}:7890"
export HTTPS_PROXY="https://{your_ip}:7890"
另外,就是要打开CFW的Allow LAN
配置,最后如果还是不行,再升级下openssl
# 升级 OpenSSL
sudo apt upgrade openssl
5.2 开机自启动
参考文章或视频链接 |
---|
[1] How to start program at Linux boot automatically |
六、用户管理
6.1 普通用户权限
在一个新安装的 Linux 操作系统中,普通用户对系统文件夹的权限通常是受到严格限制的,以确保系统安全性和稳定性。普通用户(非 root 用户)通常拥有以下文件夹的权限:
# 用户主目录。
/home/username
# 临时目录。一个公共的临时存储区域,常用于程序运行时的临时文件存储
/tmp
# /var/tmp 目录中的文件在系统重启后通常不会被清除,适合存储需要在重启后仍然可用的临时文件
/var/tmp
# 系统在登录时为每个用户动态创建的,用于存放与用户会话相关的临时文件(例如,锁文件、socket 文件等)。UID 是用户的用户 ID。
/run/user/UID
# 其他具有全局 读 权限的目录
/root:超级用户(root)的主目录,普通用户没有权限。
/etc:存放系统配置文件,普通用户一般只具有读权限。
/boot:存放启动加载器及其配置文件,普通用户没有写权限。
/var(除 /var/tmp 外):用于存放日志文件、锁文件、缓存等系统级文件,普通用户通常没有写权限(但某些子目录可能有例外)。
/opt:用于存放第三方软件包,普通用户通常没有写权限。
所以说,安装的软件如果要全局用户可见,一般只能由 root
或具有 sudo
权限的用户来进行,普通用户在Linux操作系统中没有民主,Linux是典型的中央集权设计操作系统,只有早期的OS才不是中央集权设计,未来如果区块链盛行,OS也可能接纳区块链的设计理念,回归到更高阶的分布式用户OS上来。