【问题标题】:Script to add and remove columns depending on the variable length of the line in a file根据文件中行的可变长度添加和删除列的脚本
【发布时间】:2020-08-31 21:59:27
【问题描述】:

我在文件 karan.csv 中有 n 条记录,格式如下:

A=9607738162|B=9607562681|C=20200513191434|D=|F=959852599|G=MT|H=4012|I=4012|J=9607562681|K=947100410|
A=960299773008|B=9607793008|C=20200513191327|D=|E=ST|F=959852599|G=MO|H=2001|I=2001|J=9607793008|K=947100180|
A=9607704530|B=9607839496|C=20200513191730|D=|F=959852599|G=MT|I=5012|J=9607839496|K=|

现在,如果我们注意到,列数分别为:10、11 和 9。此计数在文件中是随机的,但列数将保持不变。

现在,我想创建一个脚本,如果一行中有 11 列,则从该列(包括分隔符)中删除 $5,使其看起来与 10 列的行完全相同

A=9607738162|B=9607562681|C=20200513191434|D=|F=959852599|G=MT|H=4012|I=4012|J=9607562681|K=947100410|

并且,添加“H=|”在 $7 中,列数为 9

A=9607704530|B=9607839496|C=20200513191730|D=|F=959852599|G=MT|H=|I=5012|J=9607839496|K=|

现在我写了以下代码来实现它:

for text in $(cat /tmp/karan.csv);do
  count=`awk -F"|" '{print NF-1}' $text`
  if [ $count == 9 ]
  then
  awk  'BEGIN{FS=OFS="|"}{$7="|H"}1' $text >> /tmp/karantest2.csv
  elif [ $count == 10 ]
  then
  echo $text >> /tmp/karantest2.csv
  else
  awk -F"|" '{print $1,$2,$3,$4,$6,$7,$8,$9,$10,$11}' $text >> /tmp/karantest2.csv
  fi
  done

但在调试之后,我意识到脚本没有继续前进:

count=`awk -F"|" '{print NF-1}' $text`

任何人都可以取悦我吗?

问候

【问题讨论】:

  • 变量 text 在每次迭代中保存 CSV 文件的一行。你告诉 awk 这一行是要处理的文件的名称。当然,没有名称的文件。我原以为awk 会发出错误消息,但我通过调用awk non-existent-file 进行了尝试,确实,它没有抱怨,而是等待stdin 处理输入。
  • 我同意你的看法@user1934428。但是有没有办法将 awk 用于像“$text”这样的变量而不是文件。

标签: bash shell awk cut


【解决方案1】:

awk解决方案:

awk -F'|' '

BEGIN { OFS="|" }

NF==10 { print $1, $2, $3, $4, $5, $6, "H=", $7, $8, $9, $10 }
NF==11 { print $0 }
NF==12 { print $1, $2, $3, $4, $6, $7, $8, $9, $10, $11, $12 }

' karen.csv

提供的示例输入的输出是:

A=9607738162|B=9607562681|C=20200513191434|D=|F=959852599|G=MT|H=4012|I=4012|J=9607562681|K=947100410|
A=960299773008|B=9607793008|C=20200513191327|D=|F=959852599|G=MO|H=2001|I=2001|J=9607793008|K=947100180|
A=9607704530|B=9607839496|C=20200513191730|D=|F=959852599|G=MT|H=|I=5012|J=9607839496|K=|

【讨论】:

  • @KaranKohli。不客气。请为答案投票。
【解决方案2】:

一个 sed 解决方案,它首先在 9 列的行上插入 H=|,然后在 11 列的行上删除第 7 列:

sed -E '/^([^\|]+\|){9}$/s/(([^\|]+\|){6})/\1H=\|/;/^([^\|]+\|){11}$/s/(([^\|]+\|){4})[^\|]+\|/\1/ inputfile

如果您需要符合 POSIX 标准的命令,那么

  • 因为-E不是POSIX,你必须转义每个(){}+(以及其他特殊字符,不在此命令中),以及取消转义 \| 使其字面化;
  • 由于\+ 也不是POSIX,您需要使用更详细的\{1,\}

这是符合 POSIX 的命令:

sed '/^\([^|]\{1,\}|\)\{9\}$/s/\(\([^|]\{1,\}|\)\{6\}\)/\1H=|/;/^\([^|]\{1,\}|\)\{11\}$/s/\(\([^|]\{1,\}|\)\{4\}\)[^|]\{1,\}|/\1/' inputfile

【讨论】:

  • --E 是 solaris 机器上的非法选项。当我尝试使用 -r 时,我得到了同样的错误
  • 您好,我对 sed 命令不满意,所以我只是复制并粘贴了您的命令(当然更改了文件名)。它只是按原样打印文件,没有任何修改,而不删除或添加文件中的任何列
  • 根据我可以重现的here,我提供的命令似乎不符合 POXIS,但我不知道为什么。今天晚些时候我会看看它。
  • @KaranKohli,找到了。 \+ 不是 POSIX,因此您必须改用 \{1,\}
猜你喜欢
  • 1970-01-01
  • 2018-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多