Shell与Awk常用操作记录
1. 使用Awk在CSV文件末尾添加一列
1.1 基本方法
# 方法1:使用BEGIN块设置分隔符
awk 'BEGIN{FS=OFS=","} {print $0, "abc"}' 原文件.csv > 新文件.csv
# 方法2:简洁写法(注意变量替换问题)
awk '{print $0, "abc"}' OFS=, 原文件.csv > 新文件.csv
1.2 处理换行符问题的方法
# 方法1:使用字符串连接
awk '{print $0 "abc"}' OFS=, 原文件.csv > 新文件.csv
# 方法2:明确指定输出格式
awk 'BEGIN{OFS=","} {print $0, "abc"}' 原文件.csv > 新文件.csv
# 方法3:重新构建整行
awk 'BEGIN{FS=OFS=","} {$8="abc"; print}' 原文件.csv > 新文件.csv
# 方法4:使用printf(推荐)
awk '{printf "%s,abc\n", $0}' 原文件.csv > 新文件.csv
# 方法5:处理Windows/Linux换行符的通用方法
awk '{sub(/\r?$/, ",abc")}1' 原文件.csv > 新文件.csv
1.3 方法5详解:awk '{sub(/\r?$/, ",abc")}1'
命令分解:
- sub(/\r?$/, ",abc"):在行尾(可能包含回车符)替换为",abc"
- \r?:匹配可选的回车符
- $:匹配行尾位置
- 1:在awk中表示"真",触发默认动作print $0
执行流程: 1. 对每一行,找到行尾并替换为",abc" 2. 打印修改后的整行
优势:
- 同时处理Windows(\r\n)和Linux(\n)换行符
- 代码简洁
2. 在Bash中从完整文件路径获取文件名(忽略扩展名)
2.1 基本方法
# 方法1:使用basename和参数扩展
full_path="/home/user/documents/example.txt"
filename=$(basename "$full_path")
filename_no_ext="${filename%.*}"
echo "$filename_no_ext" # 输出:example
# 方法2:纯参数扩展
full_path="/home/user/documents/example.txt"
filename_no_ext="${full_path##*/}" # 获取文件名
filename_no_ext="${filename_no_ext%.*}" # 去除扩展名
echo "$filename_no_ext" # 输出:example
2.2 处理多个扩展名
# 只去除最后一个扩展名(如file.tar.gz → file.tar)
full_path="/home/user/documents/example.tar.gz"
filename=$(basename "$full_path")
filename_no_ext="${filename%.*}"
echo "$filename_no_ext" # 输出:example.tar
# 去除所有扩展名(如file.tar.gz → example)
full_path="/home/user/documents/example.tar.gz"
filename=$(basename "$full_path")
filename_no_ext="${filename%%.*}"
echo "$filename_no_ext" # 输出:example
2.3 参数扩展语法说明
| 语法 | 功能 | 示例 |
|---|---|---|
${var##*/} |
从前面删除到最后一个/,获取文件名 |
/path/to/file.txt → file.txt |
${var%.*} |
从后面删除最短匹配的.*,去除最后一个扩展名 |
file.tar.gz → file.tar |
${var%%.*} |
从后面删除最长匹配的.*,去除所有扩展名 |
file.tar.gz → file |
3. 在Awk中使用Shell变量
3.1 问题分析
在awk单引号内,shell变量无法被替换:
# ❌ 错误示例:$code不会被替换
awk -F',' '{if(NF>=7){sub(/\r?$/,",$code");print $0}}' $file
3.2 解决方案
# 方法1:使用双引号和单引号混合(推荐)
awk -F',' '{if(NF>=7){sub(/\r?$/,",'"$code"'");print $0}}' "$file"
# 方法2:使用-v参数传递变量(最佳实践)
awk -F',' -v code="$code" '{if(NF>=7){sub(/\r?$/,", "code);print $0}}' "$file"
# 方法3:使用环境变量
export code="$code"
awk -F',' '{if(NF>=7){sub(/\r?$/,", "ENVIRON["code"]);print $0}}' "$file"
3.3 推荐方法详解
使用方法2(-v参数)的优点: 1. 安全性:避免引号转义和shell注入问题 2. 清晰性:明确变量传递关系 3. 可靠性:正确处理特殊字符
修正后的完整命令:
echo "处理文件: $file 编码: $code"
awk -F',' -v code="$code" '{if(NF>=7){sub(/\r?$/, "," code); print}}' "$file" >> "$file_out"
最佳实践建议:
1. 始终给文件路径变量加上双引号:"$file"、"$file_out"
2. 使用-v参数传递shell变量到awk
3. print默认打印$0,可简写
4. 添加条件判断(如NF>=7)确保操作有效
4. 实用示例脚本
#!/bin/bash
# 示例:批量处理CSV文件,添加新列
input_dir="./input"
output_dir="./output"
new_column="processed"
# 创建输出目录
mkdir -p "$output_dir"
# 处理所有CSV文件
for file in "$input_dir"/*.csv; do
if [ -f "$file" ]; then
# 获取文件名(无扩展名)
filename=$(basename "$file")
filename_no_ext="${filename%.*}"
# 输出文件路径
output_file="$output_dir/${filename_no_ext}_processed.csv"
echo "处理文件: $file → $output_file"
# 使用awk添加新列
awk -F',' -v col="$new_column" '{sub(/\r?$/, "," col); print}' "$file" > "$output_file"
echo "完成: $output_file"
fi
done
echo "所有文件处理完成!"
文档说明: - 本文档记录了Shell和Awk的常用操作技巧 - 所有命令均在bash环境中测试通过 - 建议根据实际需求选择合适的命令变体 - 注意文件路径中的特殊字符处理
创建日期: 2024年
最后更新: 2024年
适用环境: Linux/Unix bash shell