用两种不同的方式编辑CSV行

时间:2019-06-18 04:45:20

标签: regex bash csv replace

我有一个bash脚本,可以输出两个CSV列。我需要在包含它们的第二列的那些行的前三位数字前加上“ f。”,并使其余的行保持完整。到目前为止,我已经尝试了不同的方法,但是每种方法都以一种或另一种方式失败了。

我主要尝试的是在第一列或第二列中使用正则表达式,以将所需的行与其余的列分开,但是我不能在不取消或弄乱的情况下同时分开和前置以某种方式处理。到目前为止,我使用过的一些命令是:$ sed $ cut和(嵌套)for循环,read-while循环,if / else和if / else / elif语句等。下面是这样的命令(失败)解决方案:

for var1 in "^.*_[^f]_.*"
do
    sed -i "" "s:$MSname::" $pathToCSV"_final.csv"
    for var2 in "^.*_f_.*"
    do
        sed -i "" "s:$MSname:f.:" $pathToCSV"_final.csv"
    done
done

这些是一些示例行:

abc_deg0014_0001_a_1.tif,British Library 1 Front Board Outside
abc_deg0014_0002_b_000.tif,British Library 1 Front Board Inside
abc_deg0014_0003_f_001r.tif,British Library 1 001r
abc_deg0014_0004_f_001v.tif,British Library 1 001v
…
abc_deg0014_0267_f_132r.tif,British Library 1 132r
abc_deg0014_0268_f_132v.tif,British Library 1 132v
abc_deg0014_0269_y_999.tif,British Library 1 Back Board Inside
abc_deg0014_0270_z_1.tif,British Library 1 Back Board Outside

这里$ MSname =大英图书馆1(由于使用不同的CSV,“大英图书馆1”部分可以更改为我需要删除/替换的其他单词,这就是为什么我使用参数扩展)。

所需结果

abc_deg0014_0002_b_000.tif,Front Board Inside
abc_deg0014_0003_f_001r.tif,f. 001r
…
abc_deg0014_0268_f_132v.tif,f. 132v
abc_deg0014_0269_y_999.tif,Back Board Inside

如果仔细观察,您会发现这些行与第一行中的其他行也通过“ f ”(在前面的行中不应该包含“ f。”的行)进行区分。他们的第二列的区别在于“ a ”,“ b ”,“ y ”和“ z “分别在第一列中)。

2 个答案:

答案 0 :(得分:0)

使用personScores(3),您可以查看第一个字段,看它是否与“ 3digits + 1 letter”相匹配,然后在这种情况下用awk打印,只需删除字段2、3和4。其他情况。例如:

f.

在您提供的示例中,它给出:

  

abc_deg0014_0001_a_1.tif,外部前面板

     

abc_deg0014_0002_b_000.tif,内部前置板

     

abc_deg0014_0003_f_001r.tif,f。 001r

     

abc_deg0014_0004_f_001v.tif,f。 001v

     

abc_deg0014_0267_f_132r.tif,f。 132r

     

abc_deg0014_0268_f_132v.tif,f。 132v

     

abc_deg0014_0269_y_999.tif,内部后挡板

     

abc_deg0014_0270_z_1.tif,外部背板

答案 1 :(得分:0)

您没有使用var1var2做任何事情,即使您这样做了,循环遍历变量并在同一输出文件上重复运行sed -i也非常浪费。理想情况下,您希望将所有修改都写入单个sed脚本中,并且只处理一次文件。

无法猜测您除了"British Library 1"之外还有哪些其他字符串,以及这些字符串是否需要采取其他不同的操作,因此我建议采取类似的方式

sed -i '/^[^,]*_f_[^,_]*,/s/,British Library 1 /,f. /
    s/,British Library 1 /,/' "${pathToCSV}_final.csv"

请注意如何将单引号中的sed脚本括在多条物理行上。第一行查找第一行中逗号之间的下划线之间的最后一个字符为f的所有行,并将",British Library 1 "替换为",f. "。 (我在这里对间距做了一些调整-希望它们对您有意义。)在下一行,我们仅用逗号替换",British Library 1 "的所有(剩余)出现;这个想法是,只有与上一行正则表达式不匹配的行仍将包含此字符串,因此我们不必进行其他正则表达式匹配。

可以轻松地将其扩展为在同一sed脚本中涵盖更多模式,而不是重复循环遍历文件并一次重写一个模式。例如,如果您的下一个任务是将Windsor Palace A替换为a.或不替换任何内容,具体取决于第一个字段中倒数第二个下划线分隔的子字段是否包含a,那应该很明显:

sed -i '/^[^,]*_f_[^,_]*,/s/,British Library 1 /,f. /
    s/,British Library 1 /,/
    /^[^,]*_a_[^,_]*,/s/,Windsor Palace A /,a. /
    s/,Windsor Palace A /,/' "${pathToCSV}_final.csv"

更多细节,正则表达式说

^       beginning of line
[^,]*   any sequence of characters which are not a comma
_f_     literal characters underscore, f, underscore
[^,_]*  any sequence of characters which are not a comma or an underscore 
,       literal comma

您应该能够看到这将针对第一列中的最后一对下划线。重要的是,切勿跳过第一个逗号,并且不要在结尾附近,在最终允许逗号列定界符之前,不要在我们专门针对的逗号之后加下划线。

最后,还要注意我们如何始终对包含文件名的变量使用双引号。在某些情况下,您可以避免这种情况,但是您必须知道自己在做什么。简便易行的经验法则是始终在变量周围加上双引号。有关完整的消息,请参见When to wrap quotes around a shell variable?