shell sed使用数组搜索并替换csv文件上的最后一列

gcxthw6b  于 2022-11-25  发布在  Shell
关注(0)|答案(3)|浏览(231)

我正在寻找一个解决方案与sed命令搜索和替换字符串的csv文件的最后一列,这里的搜索模式,我从一个数组调用.下面的脚本寻找第三和第四列,这导致在输出不匹配.
在这里我需要你的帮助,我可以告诉sed只看最后一列。
file1.txt

QCQP
TXTT
QCQT
YYTH

file2.txt

TTYY
JPEK
QCQC
TTYE

原始输出.csv

[Input]
String1

[Data]
ID,Name,Class,Context,Code
1,jack,6,QCQT,QCQP
2,john,5,QCQP,TXTT
3,jake,3,TTXX,QCQT
4,jone,3,TXTT,YYTH

下面是我在此设置中使用的脚本,但这里的sed命令搜索所有匹配项,而不是查找由逗号分隔的最后一列。

#!/bin/bash
filein=file1.txt
fileout=file2.txt
pre=$(cat $filein)
post=$(cat $fileout)
prear=($pre)
postar=($post)
typeset -p prear postar

for (( i=0; i<${#prear[@]}; ++i )); do
sed -i -e 's/'"${prear[$i]}"'/'"${postar[$i]}"'/g' output.csv
done

预期结果
output.csv

[Input]
String1

[Data]
ID,Name,Class,Context,Code
1,jack,6,QCQT,TTYY
2,john,5,QCQP,JPEK
3,jake,3,TTXX,QCQC
4,jone,3,TXTT,TTYE

使用awk命令,我可以找出类似的情况,但下面的工作与一个单一的变量,也不是与逗号分隔符,但与数组这失败。

awk -F "," '{gsub(c,d,$(NF)); print}' c=$a d=$b file.txt

另外,如果使用awk或gawk,我需要指定变量名作为输入。因为输入文件“file1.txt,file2.txt”和输出文件的.csv文件名并不总是相同的。实际上,我接受它们作为脚本中的第一个,第二个和第三个参数,然后从该变量中阅读内容。
例如:-这里用户可以选择任何名称文件作为输入。这里我不知道如何在awk/gawk中调用数组

#!/bin/bash
input1=$1
input2=$2
Output=$3

inp1=$(cat $input1)
inp2=$(cat $input2)
out=$(cat $Output)
inp1ar=($inp1)
inp2ar=($inp2)
outar=($out)

I would like to expect to call the array variable to read the contents 

gawk -i inplace '
.. some condition ..
' {inp1ar} {inp2ar} {outar}

请告知
谢谢杰

b09cbbtk

b09cbbtk1#

我会使用awk来实现这个。
第一个
但是使用sed,您可以使用file 1和file动态构建一个sed程序,然后将其应用于原始csv

sed "$(paste -d " " file1.txt file2.txt | sed 's/^/s:,/; s/ /$:,/; s/$/:/')" original.csv

逐段执行,看看它们是如何组合在一起的。
要使用“前缀”行容纳更新的csv文件:(未测试)

gawk '
  BEGIN {FS = OFS = ","}
  ARGIND == 1 {f1[FNR] = $1; next}
  ARGIND == 2 {map[f1[FNR]] = $1; next}

  BEGINFILE {start = 0; header = 1}
  start {if (header) {header = 0} else {$NF = map[$NF]}}
  {print}
  $1 == "[Data]" {start = 1}
' file1.txt file2.txt original.csv

给定您最近编辑的脚本的框架:
首先,引用变量名称至关重要cat "$input1"--如果不这样做,将导致您报告“I 'm falling as argument or some other variable name”(我作为参数或其他变量名失败)。
接下来,不需要读取脚本bash部分中的文件内容:awk会这么做。

#!/bin/bash
input1="$1"
input2="$2"
Output="$3"

gawk -i inplace '.. some condition ..' "$input1" "$input2" "$Output"

看到变量是如何在所有地方都用(双)引号括起来的吗?

68de4m5k

68de4m5k2#

在修复了与pre[]post[]数组填充相关的问题之后,OP的bash代码现在应该可以正常运行,因此,请查看awk解决方案...
假设条件:

  • file1.txtfile2.txt具有相同的行数(即,file1.txt中的每一行在file2.txt中都有一个匹配的行)
  • 没有文件包含逗号作为数据的一部分(即,逗号仅在output.csv中显示为分隔符)
  • 如果从output.csv开始的第5列在file1.txt中没有匹配,则不处理该行
  • [Data]段是output.csv中的最后一段(否则,一旦[Data]段已被处理,OP可能需要添加逻辑以关闭替换逻辑)

output.csv添加在file1.txt中没有匹配项的行:

$ cat [Input]
String1

[Data]
ID,Name,Class,Context,Code
1,jack,6,QCQT,QCQP
2,john,5,QCQP,TXTT
3,jake,3,TTXX,QCQT
4,jone,3,TXTT,YYTH
5,mary,7,XXXX,9999                 # this line should not be modified

我们将利用pastefile1.txtfile2.txt合并为一个数据集:

$ paste -d',' file1.txt file2.txt
QCQP,TTYY
TXTT,JPEK
QCQT,QCQC
YYTH,TTYE

一个awk创意:

awk '
BEGIN                  { FS=OFS=","; replace=0 }     # initially we are not in "replace" mode
FNR==NR                { map[$1]=$2; next }          # 1st file: build map[] array entries
replace && ($5 in map) { $5=map[$5] }                # 2nd file: if in "replace" mode and 5th field is an index in the map[] array then replace the 5th field 
$1 == "[Data]"         { replace=1 }                 # enable "replace" mode
1                                                    # print current line
' <(paste -d',' file1.txt file2.txt) output.csv

这会产生:

[Input]
String1

[Data]
ID,Name,Class,Context,Code
1,jack,6,QCQT,TTYY
2,john,5,QCQP,JPEK
3,jake,3,TTXX,QCQC
4,jone,3,TXTT,TTYE
5,mary,7,XXXX,9999                 # line was not modified

虽然OP的sed代码更新了原始文件(由于使用了-i标志),但这个awk解决方案 * 不 * 更新原始文件。如果OP需要更新原始文件,那么有两个选项:

  • 将此输出保存到一个临时文件,然后mv tempfile output.csv
  • 如果使用GNU awk,我们可以使用inplace模块

假设GNU awk可用,我们可以对awk代码进行以下更改,以支持output.csv的更新:

awk -i inplace '
BEGIN                  { FS=OFS=","; replace=0 }
FNR==NR                { map[$1]=$2; next }
replace && ($5 in map) { $5=map[$5] }
$1 == "[Data]"         { replace=1 }
1
' inplace::enable=0 <(paste -d',' file1.txt file2.txt) inplace::enable=1 output.csv

其中:

  • -i inplace-加载inplace模块
  • inplace::enable=0-对包含paste结果的“文件”禁用inplace处理
  • inplace::enable=1-为output.csv文件启用inplace处理

这会产生:

$ cat output.csv
[Input]
String1

[Data]
ID,Name,Class,Context,Code
1,jack,6,QCQT,TTYY
2,john,5,QCQP,JPEK
3,jake,3,TTXX,QCQC
4,jone,3,TXTT,TTYE
5,mary,7,XXXX,9999
eulz3vhy

eulz3vhy3#

这个sed应该可以:

$ cat f
ID,Name,Class,Context,Code
1,jack,6,QCQT,QCQP
2,john,5,QCQP,TXTT
3,jake,3,TTXX,QCQT
4,jone,3,TXTT,YYTH

$ sed -r 's/,(QCQP|TXTT|QCQT|YYTH)$/,aaa/' f f
ID,Name,Class,Context,Code
1,jack,6,QCQT,aaa
2,john,5,QCQP,aaa
3,jake,3,TTXX,aaa
4,jone,3,TXTT,aaa
ID,Name,Class,Context,Code
1,jack,6,QCQT,aaa
2,john,5,QCQP,aaa
3,jake,3,TTXX,aaa
4,jone,3,TXTT,aaa

但是IMHO awk更适合这个任务。

相关问题