【问题标题】:bash/awk/unix detect changes in lines of csv filesbash/awk/unix 检测 csv 文件行的变化
【发布时间】:2021-12-13 01:36:24
【问题描述】:

我有一个这种格式的时间戳:

(normal_file.csv)

timestamp
19/02/2002
19/02/2002
19/02/2002
19/02/2002
19/02/2002
19/02/2002

日期通常是统一的,但是,有些文件的日期模式不规则,例如这个例子:

(异常文件.csv)

timestamp
19/02/2002
19/02/2003
19/02/2005
19/02/2006

在我的目录中,有数百个文件,由 normal.csv 和异常.csv 组成。

我想编写一个 bash 或 awk 脚本来检测目录中所有文件中的日期模式。带有异常 .csv 的文件应该自动移动到一个新的、单独的目录(比如 dir_different/)。

目前,我尝试了以下方法:

#!/bin/bash

mkdir dir_different

for FILE in *.csv;

do
  # pipe 1: detect the changes in the line
  # pipe 2: print the timestamp column (first column, columns are comma-separated)
  awk '$1 != prev {print ; prev = $1}' < $FILE | awk -F , '{print $1}'
done

如果给定文件中的时间戳是正常的,那么只会打印一个时间戳;但是对于异常文件,会打印多个日期。

我不知道如何将异常文件与正常文件分开,我尝试了以下方法:

do
   output=$(awk 'FNR==3{print $0}' $FILE)
   echo ${output}

   if [[ ${output} =~ ([[:space:]]) ]]
   then
      mv $FILE dir_different/
   fi
done

或者有没有更简单的方法来检测行的变化并分离具有不同行的文件?感谢您的任何建议:)

【问题讨论】:

  • 你考虑过使用sort -u吗?
  • 打印所有时间戳对您来说有多重要?如果您真正想要的只是分离可以简化事情的文件。
  • @RomeoNinov:感谢您的评论和建议。 sort -u file.csv 在这种情况下不起作用,因为日期列的顺序应该保持原样而不改变它们的位置。某些文件中的日期没有按照顺序...

标签: linux bash shell awk


【解决方案1】:

假设您的“普通”CSV 文件都没有尾随换行符,这应该可以很好地进行分隔:

#!/bin/bash
mkdir -p dir_different

for FILE in *.csv;
do
        if awk '{a[$1]++}END{if(length(a)<=2){exit 1}}' "$FILE" ; then
                echo mv "$FILE" dir_different
        fi
done

在试运行之后,只需摆脱 echo :)

编辑: {a[$1]++} 这个位创建了一个数组 a,它获取每行的第一个字段作为索引,并且每次看到相同的值时都会递增。

END{if(length(a)&lt;=2){exit 1}} 检查数组中有多少元素。如果少于 3 个(如果总是有相同的日期并且我们只得到 1 个标头,1 个日期,则应该是这种情况)以 1 退出处理。

"$FILE" 是 bash 脚本的一部分,而不是 awk,我出于习惯引用了你的变量,如果你的文件名中有带空格的文件,你会明白为什么:)

【讨论】:

  • 这是一个了不起的解决方案!它非常适合手头的问题 :) 你能解释一下'{a[$1]++}END{if(length(a)&lt;=2){exit 1}}' "$FILE" 的语法吗?
  • 当然@doraemon,我会编辑我的答案并添加解释。
  • 是的,我理解“$FILE”的棘手部分——我之前花了一些时间试图理解为什么 $FILE 在保存带有空格作为变量的路径时不起作用,即使我已经附上了带有“带空格的路径”的路径。我只是发现我需要在变量中进一步添加双引号;)感谢您的出色解释!
【解决方案2】:

所以,一个“正常”文件只包含两个不同的行:

timestamp
dd/mm/yyyy

因此,测试文件是否正常很简单:

[ $(sort -u file.csv | wc -l) -eq 2 ]

这导致以下可能的解决方案:

#!/usr/bin/env bash
mkdir -p dir_different

for FILE in *.csv;
do
        if [ $(sort -u "$FILE" | wc -l) -ne 2 ] ; then
                echo mv "$FILE" dir_different
        fi
done

【讨论】:

  • 感谢您的建议。普通文件不只包含两个不同的行。如果您在第一个线程中引用 normal.csv,则普通文件的日期列对于所有行都应该相同。例如,在使用sort -u file.csv | wc -l 评估时,在一个 normal.csv 中有 47 行。之所以显示为 2,是因为awk '$1 != prev {print ; prev = $1}' &lt; file.csv 检查每个文件,只输出唯一的行。
  • 这是否意味着您的文件不止一列?如果是,您应该编辑您的问题并添加此重要信息,我认为。这可能会使您的问题对其他有类似问题的人更有用。
猜你喜欢
  • 2018-02-16
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 2019-12-23
  • 2014-10-12
  • 2018-10-08
  • 2013-01-07
  • 1970-01-01
相关资源
最近更新 更多