从每个代码的主文件中提取最旧的值

从每个代码的主文件中提取最旧的值

我需要帮助编写一个脚本,该脚本可以从主文件中提取最旧的记录并将其保存在单独的文件中。该文件包含数百个 ISIN 代码和其他数据。每个都有每日记录。完美的脚本将取出整个最旧的行并将其保存在以该 ISIN 代码命名的单独文件中。所以我猜是 split 和 grep 组合?

例子:

A 列 - ISIN 代码(即 XX1234567891)<- 2 个字母和 10 个数字

C 列 - 日期 - 2019 年 8 月 4 日

B 列和 DI - 相关数据。

有什么建议吗?请记住,我才刚刚开始使用 bash。

预先感谢您的任何帮助

以下是示例文件的链接: https://drive.google.com/file/d/1Q3qhrVlIMA7cJhDVxjxoHCipEl8sV-xo/view?usp=sharing

具有 3 个不同 ISIN 的示例: 具有 3 个不同 ISIN 的示例

具有最旧记录的一个文件: 一个包含最旧记录的文件

具有最旧记录的第二个文件: 具有最旧记录的第二个文件

第三个具有最古老记录的 - 两者的日期相同: 第三个记录最早 - 日期相同

日期采用 DD/MM/YYYY 格式(现在我在 Libre 中查看它,我可以看到日期格式更改为 MM/DD/YYYY - 但我可以稍后调整)。

答案1

尝试这个,

tail -n+2 file \
| sort -n -k 3.7,3.10 -k 3.4,3.5 -k 3.1,3.2 \
| awk '!s[$1]++{print > $1}'
  • tail -n+2 file只删除标题行
  • sort -n -k 3.7,3.10 -k 3.4,3.5 -k 3.1,3.2 对日期进行排序
  • awk '!s[$1]++{print > $1}'仅打印每个 ISIN 的第一行

如果您有YYYY/MM/DD日期格式,那么您只需执行即可sort -k3


awk唯一的解决方案:

awk '
  NR==1{next}
  {
    split($3,d,"/")
    t=mktime(d[3]" "d[2]" "d[1]" 00 00 00")
    if(!s[$1]||t<s[$1]){
      s[$1]=t
      r[$1]=$0
    }
  }
  END {
    for (i in r) { print r[i] > i}
  }' file

答案2

您在 GUI 界面中显示示例,在纯文本中列之间应该有分隔符,我使用空格作为分隔符,在脚本中用实际的分隔符替换它。

下面是我用作示例的文件:

$ cat ISIN 
XX1234567890 Bcolumn 08/04/2019 Dcolumn
XX2234567890 Bcolumn 09/03/2019 Dcolumn
XX3234567890 Bcolumn 07/05/2019 Dcolumn
XX3234567890 Bcolumn 07/05/2018 Dcolumn
XX3234567890 Bcolumn 07/05/2016 Dcolumn
XX3234567890 Bcolumn 07/05/2017 Dcolumn
XX1234567890 Bcolumn 07/05/2015 Dcolumn

下面是一个脚本,它处理输入文件中最早的 3 行,您可以调整这个数字:

#!/usr/bin/env bash

# replace ISIN with actual file name
# head -n 3 results in 3 oldest rows
# note the field separator, replace it with actual
result=$(sort --field-separator=' ' --key=3.7,3.10 --key=3.4,3.5 --key=3.1,3.2 ISIN| head -n 3)
# if input contain header line following line will take that into account, 
# uncomment it, and comment the above line
#result=$(tail -n+2 ISIN| sort --field-separator=' ' --key=3.7,3.10 --key=3.4,3.5 --key=3.1,3.2| head -n 3)

# read output line by line
# and delete exising files named as ISIN
# may be left from previous script run
while IFS='' read -r i || [[ -n "$i" ]]; do
  # extracting first column
  first=${i%% *}
  rm $first &>/dev/null
done <<<$result

# read output line by line
while IFS='' read -r i || [[ -n "$i" ]]; do
  echo "output: $i"
  # extracting first column
  first=${i%% *}
  echo "Writing to file $first"
  # append to a file with first column as a name
  echo "$i" >>$first
done <<<$result

使用实际分隔符进行调整--field-separator=' ',可能是“,”或“;”,并更改head -n 3为所需的旧行数。脚本还会从 ISIN 文件读取输入,并将其替换为您的实际文件名。

更新:脚本将行附加到 ISIN 文件,因此在第二次运行时 - 可能会出现重复的行。我添加了一个循环,删除这个旧的 ISIN 文件并再次创建,因此可以多次运行并获得正确的结果。输出文件包含一个或多个具有相同 ISIN 的行。

相关内容