![如何使用 sed 根据第 1 列和第 7 列中的模式过滤 csv 文件的结果?](https://linux22.com/image/207276/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%20sed%20%E6%A0%B9%E6%8D%AE%E7%AC%AC%201%20%E5%88%97%E5%92%8C%E7%AC%AC%207%20%E5%88%97%E4%B8%AD%E7%9A%84%E6%A8%A1%E5%BC%8F%E8%BF%87%E6%BB%A4%20csv%20%E6%96%87%E4%BB%B6%E7%9A%84%E7%BB%93%E6%9E%9C%EF%BC%9F.png)
我正在尝试编写一个 shell 脚本,扫描第 1 列和第 7 列中用户指定的值,其中 $3 与第 7 列中匹配,$2 与第一列中匹配的年份($1 是文件名)。我可以很好地匹配第七列,但在尝试添加要在第一列中匹配的变量时,不断收到错误 'sed: -e expression #1, char 7:unknown command: `2' 。不幸的是,我必须使用 sed 而不是 awk。到目前为止,这是我所拥有的:
sed -n "/"$2",[^,],[^,],[^,],[^,],[^,]*,"$3"/p" "$1"
我应该怎么解决这个问题?我是一个新手,所以欢迎所有帮助。尝试过 shellcheck 但没有帮助。该脚本在扫描第 7 列时运行良好,但添加 $2 方面会导致错误。
编辑:示例调用:
./script.sh filename "2015.2016" "South"
示例文件(“...”是内部有文本的列):
2021/2022,text,text,text,text,text,South,text,...,...
2021/2022,text,text,text,text,text,North,text,...,...
2015/2016,text,text,text,text,text,South,text,...,...
2014/2015,text,text,text,text,text,West,text,...,...
预期输出:
2015/2016,text,text,text,text,text,South,text,...,...
编辑:虽然我同意它确实不是这项工作的最佳工具,但我在玩了一下之后想出了如何使用 sed 来完成此任务:
#!/bin/bash
year="$2"
name="$3"
sed -n '/^'"$year"',\([^,]*,\)\{5\}'"$name"'\(,.*\)\{0,\}$/p' "$1"
不知道我是否会使用它,但也许它会帮助其他人。请注意,输入需要一个“.”而不是“/”,以便产生准确的结果。
答案1
sed 不是一个很好的工具,只需使用 awk:
$ cat script.sh
#!/usr/bin/env bash
awk -F',' '$1==a && $7==b' a="$2" b="$3" "$1"
$ ./script.sh file.csv "2021" "South"
2021,text,text,text,text,text,South,text
不过,由于您需要 sed 解决方案,因此使用 POSIX sed:
$ cat script.sh
#!/usr/bin/env bash
a=$(sed 's/[^^\\]/[&]/g; s/\^/\\^/g; s/\\/\\\\/g' <<< "$2")
b=$(sed 's/[^^\\]/[&]/g; s/\^/\\^/g; s/\\/\\\\/g' <<< "$3")
sed -n '/^'"$a"',\([^,]*,\)\{5\}'"$b"'\(,.*\)\{0,\}$/p' "$1"
$ ./script.sh file.csv "2021" "South"
2021,text,text,text,text,text,South,text
看是否可以使用 sed 可靠地转义正则表达式元字符为什么前两个 sed 命令是必要的,但简而言之,这是因为您需要进行文字字符串匹配,而 sed 仅支持正则表达式匹配,而不支持文字字符串匹配,因此您必须转义每个可能的正则表达式元字符(实际上您必须转义每个char ,因为任何 char 都可以是 sed 脚本分隔符,例如/
) ,使其表现得像文字字符一样。这是第二个重要线索,表明 sed 是不适合这项工作的工具(第一个是它不会将输入拆分为字段),而不是像 awk 这样只支持文字字符串匹配的工具。