我正在尝试编写一个 shell 脚本来搜索 csv 文件中的单元格值并替换同一行中的相应单元格。
下面是我的 csv 文件 ( report.csv
)
#,设备,状态
1、设备 1、已使用
2、设备 2、免费
3、设备 3、免费
这就是我想做的:
用户在执行脚本时将输入设备名称作为输入。
例如,输入设备名称:
用户输入“Device2”
下一步:脚本应该搜索设备2在report.csv
。如果发现设备2,检查中的值地位与其对应的列,如果值为自由的,将其替换为用过的,否则退出脚本设备2已在使用中。
我尝试过以下代码
#!/bin/bash
dvc=""
FILE_HOME="/tmp/test/"
update_value () {
awk -F, -v d="$dvc" '$2==d{if($3=="Free")$3="Used"; else print d "In use"; input_value;}1' \
OFS=, "$FILE_HOME"/report.csv > "$FILE_HOME"/report1.csv
mv "$FILE_HOME"/report1.csv "$FILE_HOME"/report.csv
}
input_value () {
echo -e "Enter the device name:\n"
read dvc
update_value
}
input_value
这段代码很好,当如果声明是真的。
但当如果声明是错误的,它不是input_value
从 else 部分调用函数。它只是打印设备# 正在使用与 csv 文件中的其他条目一起添加到新文件中。
我得到以下输出文件
当输入是设备2:
#,设备,状态
1、设备 1、已使用
2、设备 2、已使用
3、设备 3、空闲当输入是设备1:
#,设备,状态
设备 1 正在使用
1、设备 1、已使用
2、设备 2、空闲
3、设备 3、空闲
这是我正在做的正确方法吗?
我很高兴看到是否有不同/更好的方法来实现要求。
答案1
将您的错误消息写入stderr
.
awk -F, OFS=, -v d="$dvc" '
$2==d {
if($3=="Free") $3="Used"
else print d "In use" > "/dev/stderr"
print
}' $FILE_HOME/report.csv > $FILE_HOME/report1.csv
这将使其显示在屏幕上(如果stderr
未重定向),而不是显示在标准输出中。
话虽这么说,您可以采取一些措施来使脚本更易于使用。这个怎么样:
#!/usr/bin/awk -f
BEGIN {
FS=","
OFS=","
FILE_NAME="/tmp/test/report1.csv"
print "Enter the device name:"
getline d < "-"
}
$2==d && $3=="Free" {
$3="Used"
print > FILE_NAME
next
}
$2==d {
print d " in use" > "/dev/stderr"
}
{
print > FILE_NAME
}
调用它
$ script_name /tmp/test/report.csv
和/或bash
根据需要将其包裹起来。
答案2
您仅限于 shell 和 awk 吗?你能使用 SQLite 来存储你的数据或者至少解析它吗?
sqlite> .mode csv
sqlite> .import report.csv report
sqlite> update report set status="Used" where Device="Device2";
sqlite> select * from report;
1,Device1,Used
2,Device2,Used
3,Device3,Free
或者您可以使用更通用的编程语言(例如 Python)来完成您的任务?
import csv
with open('report.csv') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
if row['Device'] == "Device3":
row['Status'] = "Used"
print row
{'Device': 'Device1', 'Status': 'Used', '#': '1'}
{'Device': 'Device2', 'Status': 'Free', '#': '2'}
{'Device': 'Device3', 'Status': 'Used', '#': '3'}