linux的简单使用

引言

linux是操作系统最典型的具体实现,本文章不求深度的讲解linux相关的知识,而是汇总一些在软件测试工作当中可能用到的操作

背景

  • 软件开发和软件测试可能会用到
  • linux是目前服务器最常用的操作系统

linux基础命令

linux系统目录结构

查看系统的网络状态 —ifconfig
判断远端网络功能是否正常—ping
目录操作:查看目录— ls
目录操作:切换目录— cd
目录操作:查看路径—pwd
目录操作:创建目录— mkdir
文件操作:创建文件—touch
目录操作:删除目录—rm/rmdir
文件操作: 移动文件— mv
文件操作:   复制文件— cp
文件操作:  文件重命名—rename
文件编辑—vi
文件操作:  查看文件内容—cat/more/less
文件操作:  查看文件头/尾部内容—head /tail
查找文件命令 — find
查找包括字符串的文件 —grep
查看系统程序执行—ps
中止进程执行—kill
查看内存进程情况—top
压缩或解压文件 — gzip
压缩或解压文件 — tar
*.tar 用 tar –xvf 解压
*.gz 用 gzip -d或者gunzip 解压
*.tar.gz和*.tgz 用 tar –xzf 解压
*.bz2 用 bzip2 -d或者用bunzip2 解压
*.tar.bz2用tar –xjf 解压
*.Z 用 uncompress 解压
*.tar.Z 用tar –xZf 解压
*.rar 用 unrar 解压
*.zip 用 unzip 解压
显示指定的目录或文件所占用的磁盘空间—du
显示磁盘的使用状况—df
新建用户—useradd
删除用户—userdel
新增用户组——groupadd
删除用户组groupdel
修改密码——passwd
切换用户——su
grep grep_code grepfile* --color
ps -ef | grep java

管道符的使用

在Linux中,管道符(| 是一种强大的命令组合工具,用于将前一个命令的输出直接作为后一个命令的输入。这种机制允许用户将多个简单命令组合成复杂的操作,大幅提升效率。以下是管道符的核心用法、经典场景及注意事项:

一、基本语法与原理

1. 语法格式

命令1 | 命令2 | 命令3 ...
  • 工作流程
    1. 命令1 执行并产生输出
    2. 管道符 | 将输出传递给 命令2 作为输入
    3. 命令2 处理输入并产生新的输出,依此类推...

2. 关键点

  • 数据流单向流动:从左到右,不可逆向。
  • 仅传递标准输出(stdout):错误输出(stderr)不会通过管道传递,需单独处理(如 2>&1)。

二、经典应用场景

1. 过滤与搜索

  • 示例1:查找包含关键词的进程
    ps -ef | grep java  # 查找Java相关进程
    
  • 示例2:统计目录下的文件数量
    ls -l | wc -l  # 统计当前目录文件行数(含总用量行)
    

2. 文本处理流水线

  • 示例:提取日志中的错误信息并统计次数
    cat app.log | grep ERROR | awk '{print $4}' | sort | uniq -c
    
    • cat app.log:读取日志文件
    • grep ERROR:过滤包含ERROR的行
    • awk '{print $4}':提取第4列(假设为错误类型)
    • sort | uniq -c:排序并统计重复次数

3. 实时监控与格式化

  • 示例:监控CPU使用率并格式化输出
    top -b -n 1 | grep Cpu | awk '{print "CPU使用率: " $2 "%" }'
    
    • top -b -n 1:以批处理模式执行一次top
    • grep Cpu:提取CPU行
    • awk:格式化输出为易读文本

4. 数据传输与压缩

  • 示例:远程备份文件并压缩
    tar -cvf - /data | ssh user@remote "cat > /backup/data.tar"
    
    • tar -cvf - /data:将/data目录打包(- 表示输出到标准输出)
    • ssh ... "cat > /backup/data.tar":通过SSH将数据写入远程文件

三、高级技巧与组合命令

1. 多管道串联

  • 示例:查找最大的10个文件并格式化输出
    find / -type f -exec du -h {} + | sort -rh | head -n 10
    
    • find / -type f -exec du -h {} +:递归查找所有文件并显示大小
    • sort -rh:按大小降序排序(-h 处理人类可读格式)
    • head -n 10:取前10条

2. 结合xargs执行批量操作

  • 示例:删除30天前的日志文件
    find /var/log -type f -mtime +30 | xargs rm -f
    
    • find ... -mtime +30:查找30天前修改的文件
    • xargs rm -f:将文件名作为参数传递给rm命令

3. 处理错误输出

  • 示例:捕获并记录错误日志
    command_that_might_fail 2>&1 | tee error.log
    
    • 2>&1:将错误输出(stderr)重定向到标准输出(stdout)
    • tee error.log:同时输出到屏幕和文件

四、注意事项与常见陷阱

1. 管道命令的执行顺序

  • 管道左侧的命令未执行完时,右侧命令可能已开始处理数据(流式处理)。
  • 示例
    echo "1\n2\n3" | while read line; do sleep 1; echo $line; done
    
    输出会逐行延迟1秒显示,而非等待全部输入后一次性处理。

2. 管道中的变量作用域问题

  • bash 中,管道右侧的命令会在子shell中执行,导致变量无法传递到父shell。
  • 错误示例
    echo "hello" | var=$(cat); echo $var  # 输出为空
    
  • 正确方式(避免子shell):
    var=$(echo "hello"); echo $var  # 输出hello
    

3. 处理大量数据时的性能

  • 管道链过长可能导致性能下降,可考虑:
    • 使用临时文件分段处理
    • 优先选择原生支持多阶段处理的工具(如 awksed

五、管道符 vs 重定向符

符号 功能 示例
> 输出重定向到文件 ls > files.txt
< 文件内容作为命令输入 wc -l < files.txt
| 命令输出作为另一个命令输入 `ls -l
>> 追加输出到文件 echo "text" >> log.txt
2> 重定向错误输出 command 2> error.log
2>&1 合并错误输出和标准输出 command 2>&1 | grep "ERROR"

六、实用案例:监控服务器负载

while true; do 
  uptime | awk -F'load average:' '{print $2}' | tr -d '\n' | tee -a load.log; 
  sleep 60; 
done
  • 每分钟记录一次系统负载到 load.log
  • uptime:获取系统负载信息
  • awk:提取负载值部分
  • tr -d '\n':删除换行符
  • tee -a load.log:同时输出到屏幕和追加到文件

总结

管道符是Linux命令行的核心工具之一,通过组合简单命令可以实现复杂功能。熟练掌握管道的使用能大幅提升运维效率,但需注意数据流方向、错误处理和性能问题。建议结合 grepawksedxargs 等工具深入实践,逐步构建强大的命令组合。

shell脚本语言

shell脚本在实际软件工程中的使用

在软件工程中,Shell脚本常用于自动化构建、部署、监控、测试等环节,以下是6个典型应用场景及代码实现:

1. 自动化部署脚本(Git拉取+服务重启)

#!/bin/bash
# 部署脚本:拉取代码 → 编译 → 重启服务

# 配置信息
APP_DIR="/opt/myapp"
GIT_REPO="git@github.com:user/myapp.git"
BRANCH="main"
LOG_FILE="/var/log/deploy.log"

# 日志函数
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
}

# 错误处理
handle_error() {
  log "Error: $1"
  echo "部署失败: $1"
  exit 1
}

# 主流程
log "开始部署..."

# 拉取代码
cd $APP_DIR || handle_error "应用目录不存在"
git pull origin $BRANCH || handle_error "Git拉取失败"

# 编译(示例:Maven项目)
if [ -f "pom.xml" ]; then
  mvn clean package -DskipTests || handle_error "编译失败"
fi

# 重启服务
systemctl restart myapp.service || handle_error "服务重启失败"

# 检查服务状态
sleep 5
if ! systemctl is-active --quiet myapp.service; then
  handle_error "服务未正常启动"
fi

log "部署成功!"
echo "部署完成"

2. 定时备份脚本(数据库+文件)

#!/bin/bash
# 定时备份脚本:备份数据库和重要文件

# 配置信息
BACKUP_DIR="/data/backups"
DB_USER="root"
DB_PASS="password"
DB_NAME="mydb"
FILES_TO_BACKUP="/opt/myapp/config /var/www/html"
RETENTION_DAYS=7

# 创建备份目录
mkdir -p $BACKUP_DIR/$(date +%Y%m%d)

# 备份数据库
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME > $BACKUP_DIR/$(date +%Y%m%d)/db_backup.sql
if [ $? -ne 0 ]; then
  echo "数据库备份失败" >&2
  exit 1
fi

# 备份文件
tar -czf $BACKUP_DIR/$(date +%Y%m%d)/files_backup.tar.gz $FILES_TO_BACKUP
if [ $? -ne 0 ]; then
  echo "文件备份失败" >&2
  exit 1
fi

# 删除旧备份
find $BACKUP_DIR -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \;

echo "备份完成: $BACKUP_DIR/$(date +%Y%m%d)"

3. 服务监控与自动恢复

#!/bin/bash
# 服务监控脚本:检测服务状态,异常时自动重启

# 配置信息
SERVICE_NAME="nginx"
LOG_FILE="/var/log/service_monitor.log"
RESTART_THRESHOLD=3  # 连续失败次数触发重启

# 日志函数
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
}

# 检查服务状态
status=$(systemctl is-active $SERVICE_NAME)
if [ "$status" != "active" ]; then
  log "服务 $SERVICE_NAME 未运行"
  
  # 获取失败次数
  FAIL_COUNT_FILE="/tmp/${SERVICE_NAME}_fail_count"
  if [ -f "$FAIL_COUNT_FILE" ]; then
    fail_count=$(cat $FAIL_COUNT_FILE)
  else
    fail_count=0
  fi
  
  # 累计失败次数
  ((fail_count++))
  echo $fail_count > $FAIL_COUNT_FILE
  
  # 达到阈值则重启
  if [ $fail_count -ge $RESTART_THRESHOLD ]; then
    log "尝试重启 $SERVICE_NAME (失败次数: $fail_count)"
    systemctl restart $SERVICE_NAME
    
    # 验证重启结果
    sleep 2
    if [ "$(systemctl is-active $SERVICE_NAME)" = "active" ]; then
      log "$SERVICE_NAME 重启成功"
      echo 0 > $FAIL_COUNT_FILE  # 重置计数器
    else
      log "$SERVICE_NAME 重启失败,通知管理员"
      # 发送邮件或消息通知管理员
      echo "服务 $SERVICE_NAME 连续失败 $RESTART_THRESHOLD 次,重启失败!" | mail -s "服务告警" admin@example.com
    fi
  else
    log "未达到重启阈值 (当前: $fail_count/$RESTART_THRESHOLD)"
  fi
else
  # 服务正常,重置计数器
  if [ -f "/tmp/${SERVICE_NAME}_fail_count" ]; then
    echo 0 > /tmp/${SERVICE_NAME}_fail_count
  fi
  log "$SERVICE_NAME 运行正常"
fi

4. 代码质量检查(结合Git Hooks)

#!/bin/bash
# Git提交前检查:代码格式、单元测试

# 配置信息
SOURCE_DIR="src"
TEST_DIR="test"
LOG_FILE="/var/log/code_check.log"

# 日志函数
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
}

# 检查代码格式(示例:Python)
log "开始代码格式检查..."
flake8 $SOURCE_DIR
if [ $? -ne 0 ]; then
  log "代码格式检查失败"
  echo "代码格式错误,请修复后再提交!" >&2
  exit 1
fi

# 运行单元测试(示例:Python)
log "开始单元测试..."
pytest $TEST_DIR
if [ $? -ne 0 ]; then
  log "单元测试失败"
  echo "单元测试未通过,请修复后再提交!" >&2
  exit 1
fi

log "代码检查通过"
echo "代码检查通过"
exit 0

5. 批量文件处理(日志分析)

#!/bin/bash
# 日志分析脚本:统计HTTP请求状态码分布

# 配置信息
LOG_DIR="/var/log/nginx"
OUTPUT_FILE="/tmp/nginx_stats_$(date +%Y%m%d).txt"

# 初始化输出文件
echo "HTTP状态码统计 $(date)" > $OUTPUT_FILE
echo "------------------------" >> $OUTPUT_FILE

# 统计各状态码数量
for file in $LOG_DIR/access.log*; do
  if [ -f "$file" ]; then
    echo "分析文件: $file"
    # 提取状态码并统计
    awk '{print $9}' "$file" | sort | uniq -c | sort -nr >> $OUTPUT_FILE
  fi
done

# 计算总请求数
total=$(grep -v '^-' $OUTPUT_FILE | awk '{sum+=$1} END {print sum}')
echo "总请求数: $total" >> $OUTPUT_FILE

echo "日志分析完成,结果已保存到: $OUTPUT_FILE"

6. 环境初始化脚本(多服务配置)

#!/bin/bash
# 环境初始化脚本:配置开发环境依赖

# 配置信息
USERNAME="developer"
GROUPNAME="developers"
WORK_DIR="/workspace"

# 检查是否为root用户
if [ "$(id -u)" -ne 0 ]; then
  echo "请使用root用户运行此脚本" >&2
  exit 1
fi

# 创建用户和工作目录
useradd -m -g $GROUPNAME $USERNAME
mkdir -p $WORK_DIR
chown -R $USERNAME:$GROUPNAME $WORK_DIR

# 安装基础软件
echo "安装基础软件..."
apt-get update
apt-get install -y git vim wget curl

# 安装语言环境(示例:Python)
echo "安装Python环境..."
apt-get install -y python3 python3-pip python3-venv

# 配置SSH密钥
echo "配置SSH密钥..."
mkdir -p /home/$USERNAME/.ssh
chmod 700 /home/$USERNAME/.ssh
touch /home/$USERNAME/.ssh/authorized_keys
chmod 600 /home/$USERNAME/.ssh/authorized_keys
chown -R $USERNAME:$GROUPNAME /home/$USERNAME/.ssh

# 配置Docker(可选)
if [ "$1" = "--with-docker" ]; then
  echo "安装Docker..."
  apt-get install -y docker.io
  usermod -aG docker $USERNAME
fi

echo "环境初始化完成!"
echo "用户: $USERNAME"
echo "工作目录: $WORK_DIR"

应用场景总结

  1. 自动化部署:减少人工操作,确保部署一致性。
  2. 定时任务:定期执行备份、清理等操作,避免人工遗漏。
  3. 监控告警:实时监测服务状态,异常时自动响应。
  4. 代码质量保障:集成到Git工作流中,防止低质量代码提交。
  5. 批量数据处理:高效分析日志、转换文件格式等。
  6. 环境标准化:快速搭建开发/测试/生产环境,减少配置差异。

最佳实践

  • 使用函数封装重复逻辑,提高脚本可读性;
  • 添加错误处理和日志记录,便于问题排查;
  • 通过参数化配置增强脚本灵活性;
  • 先在测试环境验证,再应用到生产环境。
    好的,我将逐行解释这个部署脚本的功能和实现逻辑。这个脚本的核心是自动化完成代码拉取、编译和服务重启的过程,并包含了错误处理和日志记录功能。

脚本解析

#!/bin/bash
# 部署脚本:拉取代码 → 编译 → 重启服务

# 配置信息
APP_DIR="/opt/myapp"
GIT_REPO="git@github.com:user/myapp.git"
BRANCH="main"
LOG_FILE="/var/log/deploy.log"

这部分是脚本的开头,主要做了两件事:

  • #!/bin/bash:指定脚本使用Bash shell执行
  • 定义了几个全局变量,用于存储部署所需的配置信息:
    • APP_DIR:应用程序的目录
    • GIT_REPO:Git仓库地址
    • BRANCH:要部署的分支
    • LOG_FILE:日志文件路径
# 日志函数
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
}

# 错误处理
handle_error() {
  log "Error: $1"
  echo "部署失败: $1"
  exit 1
}

这里定义了两个函数:

  • log():用于记录日志,会在每条日志前加上时间戳,并将内容追加到LOG_FILE指定的文件中
  • handle_error():用于错误处理,它会记录错误日志,打印错误信息,然后终止脚本执行(返回状态码1)
# 主流程
log "开始部署..."

# 拉取代码
cd $APP_DIR || handle_error "应用目录不存在"
git pull origin $BRANCH || handle_error "Git拉取失败"

这是部署的第一个主要步骤:拉取代码。脚本会:

  1. 切换到应用目录(cd $APP_DIR),如果目录不存在则调用handle_error终止脚本
  2. 执行git pull命令从远程仓库拉取最新代码,如果失败则终止脚本
# 编译(示例:Maven项目)
if [ -f "pom.xml" ]; then
  mvn clean package -DskipTests || handle_error "编译失败"
fi

这部分处理代码编译:

  • 首先检查当前目录下是否存在pom.xml文件(Maven项目的标识)
  • 如果存在,则执行mvn clean package -DskipTests命令进行编译打包
  • -DskipTests参数表示跳过测试,这在生产环境部署中很常见
  • 如果编译失败,调用handle_error终止脚本
# 重启服务
systemctl restart myapp.service || handle_error "服务重启失败"

# 检查服务状态
sleep 5
if ! systemctl is-active --quiet myapp.service; then
  handle_error "服务未正常启动"
fi

这部分处理服务重启和状态检查:

  1. 使用systemctl restart命令重启服务,如果失败则终止脚本
  2. 等待5秒(给服务足够的启动时间)
  3. 使用systemctl is-active命令检查服务是否处于活跃状态
  4. 如果服务没有成功启动,调用handle_error终止脚本
log "部署成功!"
echo "部署完成"

如果所有步骤都成功执行,脚本会记录成功日志并打印完成信息。

关键技术点说明

  1. 错误处理机制:脚本使用|| handle_error的方式处理命令执行失败的情况,这是Bash中常用的错误处理模式。例如:

    command || handle_error "命令执行失败"
    

    这种写法的意思是:如果command执行失败(返回非零状态码),则执行handle_error函数。

  2. 日志记录:脚本通过自定义的log()函数实现日志记录,这样可以确保所有日志都有统一的时间戳格式,并且方便后续查看和分析。

  3. 服务状态检查:在重启服务后等待5秒再检查状态,这是一个简单但有效的方法,可以避免因为服务启动较慢而误判。

  4. Maven项目编译:通过检查pom.xml文件来判断是否为Maven项目,这是一种常见的项目类型识别方法。

这个脚本设计得很专业,包含了部署过程中的关键步骤和必要的错误处理,能够有效减少人工干预,提高部署效率。

posted @ 2025-05-23 23:57  莫西无邪  阅读(13)  评论(0)    收藏  举报