在 bash 中,我必须询问第一个 csv 文件、第二个 csv 文件中的每一行以及放入第三个 csv 文件的答案

在 bash 中,我必须询问第一个 csv 文件、第二个 csv 文件中的每一行以及放入第三个 csv 文件的答案

在 bash 中,我必须询问第一个 csv 文件、第二个 csv 文件中的每一行以及第三个 csv 文件中的答案...

第一个文件。例如aaa.csv

aaa
bbb
aaa
aaa
ccc
fff
aaa

第二个文件,例如bbb.csv

aaa;111
bbb;222
ccc;333
ddd;444
eee;555
ggg;666

第三个文件,例如ccc.csv

aaa;111
bbb;222
aaa;111
aaa;111
ccc;333
fff;
aaa;111

这可能吗?在这个空白处可能是错误的词或其他东西。当我使用 then 时,只有当 111 出现 aaa 时,才cat bbb.csv | grep -f aaa.csv > ccc.csv用部分常见的 the 来回答。aaa.csv

答案1

注释中的另一种可能的方法可以使用awk更改的文件顺序:

awk -F';' 'FNR == NR { m[$1] = $2; next; } { if ($1 in m) { print $1 ";" m[$1]; } else { print $1 ";FALSE"; } }' bbb aaa

首先,我们读取文件 bbb 将值存储在数组中,其中包含第一列的键值,然后读取文件 aaa 并检查数组中是否存在键并相应地打印。
结果:

aaa;111
bbb;222
aaa;111
aaa;111
ccc;333
fff;FALSE
aaa;111

答案2

你可以这样做:

while read linea
do
grep "$linea" bbb.csv >> ccc.csv || echo "$linea:FALSE" >> ccc.csv
done < aaa.csv

$ cat ccc.csv 
aaa;111 
bbb;222 
aaa;111 
aaa;111 
ccc;333 
fff:FALSE
aaa;111

答案3

一些元 sed 怎么样:

sed "$(sed 's^\(.*\);\(.*\)^s/\1/\1;\2/;tx^;$as/.*/&;FALSE/\n:x' bbb.csv)" aaa.csv

内部 sed 表达式转换bbb.csv为如下 sed 程序:

s/aaa/aaa;111/;tx
s/bbb/bbb;222/;tx
s/ccc/ccc;333/;tx
s/ddd/ddd;444/;tx
s/eee/eee;555/;tx
s/ggg/ggg;666/;tx
s/.*/&;FALSE/
:x

然后由外部 sed 解释以转换aaa.csv为所需的输出:

aaa;111
bbb;222
aaa;111
aaa;111
ccc;333
fff;FALSE
aaa;111

请注意tx生成的 sed 程序中的 。x:如果前面的s替换匹配,这些是 sed 条件跳转到标签。这允许最后插入一个包罗万象的语句来替换“FALSE”文本。

这个答案需要注意的是它不会扩展到大bbb.csv文件,因为生成的整个程序都是在命令行上传递的。如果这是一个问题,可以将生成的程序放入临时文件中:

sed 's^\(.*\);\(.*\)^s/\1/\1;\2/;tx^;$as/.*/&;FALSE/\n:x' bbb.csv > bbb.tmp.sed
sed -f bbb.tmp.sed aaa.csv > ccc.csv

如果最终非常大,这仍然会受到限制bbb.tmp.sed- 我认为 sed 会尝试将整个文件读入内存。

答案4

我强烈建议使用 Python 而不是任何 shell 工具来编写这个特定的脚本,因为 Python 的标准库包含一个 CSV 解析器,它实际上可以处理 CSV 语法中的所有古怪问题。你会做这样的事情:

import csv
import sys

# sys.argv[1] = "aaa.csv", sys.argv[2] = "bbb.csv"
# sys.argv[3] = default value for mapping
# output written to stdout

with open(sys.argv[2], "rt") as f:
    rd = csv.reader(f, dialect="unix", delimiter=";")
    mapping = { row[0] : row[1] for row in rd }

with open(sys.argv[1], "rt") as f:
    rd = csv.reader(f, dialect="unix", delimiter=";")
    wr = csv.writer(sys.stdout, dialect="unix", delimiter=";",
                    quoting=csv.QUOTE_MINIMAL)

    for row in rd:
        wr.writerow([row[0], mapping.get(row[0], sys.argv[3])])

然后运行它,例如python munge.py aaa.csv bbb.csv "" > ccc.csv

一般来说,如果不清楚如何在 shell 脚本中执行某些操作,请考虑不在 shell 脚本中执行此操作。除非对任意硬性安装的可移植性比还要别的吗(例如,在 Autoconf 宏的内部)您会更乐意编写 Perl、Python、Ruby、node.js 等。

相关内容