如何从一个文件中搜索字符串并在Linux中更新到另一个文件

时间:2019-02-18 13:43:14

标签: linux unix awk grep

我有两个文件,我要从一个文件中一个一个地搜索字符串,然后将记录更新到另一个文件中。说我有文本文件A.csv

TABLE1, ABC_STRING
TABLE2, ABC_STRING
TABLE3, ABC_STRING

B.csv

TABLEA,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLEB,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE1,SOMEVALUE,ABC_INT,NULL,ABC_INT
TABLEC,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE2,SOMEVALUE,ABC_INT,NULL,ABC_INT
TABLE3,SOMEVALUE,ABC_INT,NULL,ABC_INT

期望在新文件中输出,例如:

TABLEA,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLEB,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE1,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLEC,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE2,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE3,SOMEVALUE,ABC_STRING,NULL,ABC_STRING

我尝试过这样:

for i in $(grep -w "ABC_STRING" A.csv | awk -F ',' '{print $1}'); do
grep -w "$i" B.csv | sed 's/ABC_INT/ABC_STRING/g'
done | more

我不确定如何编写命令来复制每一行,并检查是否包含该字符串(如果可用)。如果没有将其写入同一C.csv,请替换并写入C.csv。谁能提供符合我要求的代码段。

3 个答案:

答案 0 :(得分:2)

awk -F', *' -v OFS=',' 'NR==FNR{m[$1]=$2; next} $1 in m{$3=$5=m[$1]} 1' A.csv B.csv > C.csv

答案 1 :(得分:1)

您可以尝试Perl

perl -pe ' 
         BEGIN { %kv=map{chomp;split(",")} qx(cat A.csv) }  
         /^(.+?),/ and $kv{$1} and s/ABC_INT/ABC_STRING/g 
'

使用给定的输入

$  perl -pe ' BEGIN {%kv=map{chomp;split(",")} qx(cat A.csv)}  /^(.+?),/ and $kv{$1} and s/ABC_INT/ABC_STRING/g ' B.csv
TABLEA,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLEB,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE1,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLEC,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE2,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE3,SOMEVALUE,ABC_STRING,NULL,ABC_STRING

$

答案 2 :(得分:0)

因为unix

cat <<EOF >A.csv
TABLE1, ABC_STRING
TABLE2, ABC_STRING
TABLE3, ABC_STRING
EOF

cat <<EOF >B.csv
TABLEA,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLEB,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE1,SOMEVALUE,ABC_INT,NULL,ABC_INT
TABLEC,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
TABLE2,SOMEVALUE,ABC_INT,NULL,ABC_INT
TABLE3,SOMEVALUE,ABC_INT,NULL,ABC_INT
EOF


# join the first file on the first field
# with the second file on the second field
# print unmatched lines from the second file
# the unknown matches are substituted with ##
# the output is complicated - we output the matched correct line (6 fields)
# and after it we output the original second file (6 fields)
# when there is no match, the last field from the correct line 
# is the empty separator '##' 
# we can filter is later with sed
join -11 -22 -t, -a2 -e'##' -o 2.1,2.2,2.3,1.2,2.5,1.2,2.1,2.2,2.3,2.4,2.5,2.6 <(
    # dunno what the spaces are doing in A.csv, remove them
    <A.csv tr -d ' ' | 
    # sort the file on the first field
    sort -k1 -t,
) <(
    # add a number of the lines to the second file
    # so we can sort it like the original file later
    <B.csv nl -s, -w1 | 
    # sort it on the second field (the first field is the number now)
    sort -k2 -t,
) |
# here the output looks like: 
# 6,TABLE3,SOMEVALUE,ABC_STRING,NULL,ABC_STRING,6,TABLE3,SOMEVALUE,ABC_INT,NULL,ABC_INT
# 1,TABLEA,SOMEVALUE,##,NULL,##,1,TABLEA,SOMEVALUE,ABC_STRING,NULL,ABC_STRING
# remove the first 6 fields from the lines with `##,` they were not matched
sed 's/.*,##,//' |
# extract first 6 fields, less to sort, operation is cheap
cut -d, -f1-6 |
# sort on the field numerical. This is the numbers we inserted in the second file
sort -k1 -t, -n |
# extract 5 lines from the original
cut -d, -f2-6