【问题标题】:compare csv files with bash\awk\shell将 csv 文件与 bash\awk\shell 进行比较
【发布时间】:2014-11-27 09:23:41
【问题描述】:

我编写了在 csv 文件之间进行比较的脚本。 但我还是有问题 我需要它永远是

5 个值 - 空格 - 5 个值

问题是有些行只包含4个值,所以我需要添加而不是缺失值空间列

输入:

文件1:

1,1,1,1
3,3,3,3,3

文件2:

2,2,2,2
4,4,4,4,4

现在结果如下所示:

1,1,1,1, ,2,2,2,2
3,3,3,3,3, ,4,4,4,4,4

我需要这样的结果:

1,1,1,1, , , 2,2,2,2,*space* 
3,3,3,3,3, ,4,4,4,4,4

这是我的代码:

#! /bin/bash

#------------------------------------------------------------------------------
#
# Description: Joins the files vartically based on the file extensions.
#
# Usage      : ./joinfile directory1 directory2
#
#------------------------------------------------------------------------------

#---- Variables ---------------------------------------------------------------

resultfile="resultfile.csv"

#---- Main --------------------------------------------------------------------

# Checking if two arguments are provided, if not, display usage info, and exit.
if [ "$#" -ne 2 ]
then
   echo "Usage: $0 directory1 directory2"
   exit 1
fi

# Checking if any of the arguments provided is not a directory.
if [ ! -d "$1" -o ! -d "$2" ]
then
   if [ ! -d "$1" ]
   then
      echo "Error: $1 is not a valid directory"
   fi

   if [ ! -d "$2" ]
   then
      echo "Error: $2 is not a valid directory"
   fi

   exit 1
fi

# Removing the end slash from the arguments, if user had provided.
dir1=$(echo "$1" | sed 's/\/$//')
dir2=$(echo "$2" | sed 's/\/$//')

# Creating an array of files having ^ in their filenames.
filearr=( $(ls "$dir1"/*^* "$dir2"/*^*) )

# Getting filearr length.
filearrlen=${#filearr[@]}

# Creating an array of extensions.
for (( i=0; i<"$filearrlen"; i++ ))
do
   extarr+=(${filearr[i]##*^})
done

# Removing duplicates and the last extension from an extarr.
OLDIFS="$IFS"
IFS=$'\n'
newextarr=($(for i in "${extarr[@]}"; do echo "$i" | sed 's/\.[^.]*$//'; done | sort -du))
IFS="$OLDIFS"

# Getting newextarr length.
newextarrlen=${#newextarr[@]}

# Removing the previous outfile, if exists.
if [ -e "$resultfile" ]
then
   rm "$resultfile"
fi

# Joning the files vertically based on the extensions.
for (( i=0; i<"$newextarrlen"; i++ ))
do
   ext="${newextarr[i]}"
    echo "Handling ==> $ext"
   # Getting files with similar extensions.
   joinfiles=($(for j in "${filearr[@]}"; do echo "$j" | grep "\^$ext"; done))

   # Getting joinfiles array length.
   joinfileslen=${#joinfiles[@]}

   # Making a list of files to be pasted.
   for (( k=0; k<"$joinfileslen"; k++))
   do
      pastefiles+="${joinfiles[k]} "
        dos2unix "${joinfiles[k]}" 2>/dev/null
        cat "${joinfiles[k]}" | grep "^[ \t]*([0-9]* [0-9]*)," | sed 's/^[ \t]*//g'  | sort -t, -       k1 | cut -d',' -f1- >.ext_${k}_tags.csv
   done

   # Executing paste command.
   echo "==> ${ext}" >> "$resultfile"

awk 'BEGIN{ FS = "," }
{
if(FNR == NR){ a[$1] = $0 } else{ b[$1] = $0 }

for(i in a) { 
if (i in b) 
{ c[i]=a[i]", ,"b[i]; if (a[i] == b[i] ) { c[i]="True,"c[i]; } else { c[i]="False,"c[i]; } 
} else { c[i]="False,"a[i]", ,"i",MISSING-MISSING-MISSING";}
}
for(i in b) { 
if (! i in a) { c[i]="False,"i",MISSING-MISSING-MISSING, ,"b[i]; }
}
}
END{
for (i in c){ print c[i]; }
}
' ".ext_0_tags.csv" ".ext_1_tags.csv"|sort -t, -k1 >> "$resultfile"

rm -f ".ext_0_tags.csv" ".ext_1_tags.csv"

done

#---- End ---------------------------------------------------------------------

【问题讨论】:

  • 请仅发布代码的相关部分以提供最小示例。
  • @TomFenech,好的,我认为它更清楚
  • 您需要编辑您的问题并删除所有与问题无关的部分。

标签: bash shell awk


【解决方案1】:

这是解决问题的一种方法:

awk -F, '{a[FNR]=a[FNR] sprintf("%s,%s,%s,%s,%s%s",$1,$2,$3,$4,($5==""?" ":$5),(NR==FNR?", ,":""))}
END{for(i=1;i<=FNR;++i)print a[i]}' file1.txt file2.txt

这将使用数组将您的两个文件连接在一起。 sprintf 语句中的%s 采用列的值,如果第五列为空,则采用空格。如果正在处理第一个文件,则最后的 %s 将替换为逗号。处理完所有记录后,将打印数组的元素。

这里做了一些假设:假设只有第五列可以为空,并且两个文件中有相同数量的记录。

输出:

1,1,1,1, , ,2,2,2,2,
3,3,3,3,3, ,4,4,4,4,4

【讨论】:

  • 你试过吗?您可以按照我上面的建议编辑您的问题吗?
  • 我认为您可以通过另一种方式帮助我 我有结果文件:t,1,1,1,1, ,2,2,2,2 t,3,3,3,3 ,3, , 4,4,4,4,4 第一列总是固定的 我需要这样的结果: t,1,1,1,1, , ,2,2,2,2,space i> t,3,3,3,3,3, ,4,4,4,4,4
【解决方案2】:

另一个 awk

将字段分隔符和输出字段分隔符设置为,
如果少于 5 个字段,请将字段 5 设置为空格。 将数组设置为行。 如果第二个文件打印保存的行和第二个文件中的行。

awk -F, -vOFS=, 'NF<5{$5=" "}{a[NR]=$0}FNR!=NR{print a[FNR]," ",$0}' file file2

1,1,1,1, , ,2,2,2,2,
3,3,3,3,3, ,4,4,4,4,4

我假设行中只有 4 个和 5 个字段,就好像少于 4 个那样,这不会用空格填充所有空白字段。 还假设只有两个文件。

【讨论】:

  • 这是一个更好的方法!
猜你喜欢
  • 1970-01-01
  • 2016-10-18
  • 2016-07-24
  • 1970-01-01
  • 2011-01-06
  • 1970-01-01
  • 2020-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多