【问题标题】:Create one file per date with only the file names that correspond to that date每个日期创建一个文件,仅包含与该日期对应的文件名
【发布时间】:2019-06-21 08:46:19
【问题描述】:

给定一个带有文件名列表(带有文件路径)的单个文件,例如:

input.txt (contents):
/2018/06/01/abc.txt
/2018/06/01/xyz.txt
/2018/06/02/abc.txt
/2018/06/02/xyz.txt
/2018/06/03/xyz.txt
/2018/06/03/abc.txt
/2018/06/01/ghi.txt

… 必须每个日期创建一个文件,其中仅包含与该日期对应的文件名 (全部使用标准的 Unix 命令) 例如, 预期输出:

cat 2018-06-01.txt =>
/2018/06/01/abc.txt
/2018/06/01/xyz.txt
/2018/06/01/ghi.txt

cat 2018-06-02.txt =>
/2018/06/02/abc.txt
/2018/06/02/xyz.txt

所有其他日期也是如此。

【问题讨论】:

  • 您可以遍历该文件并为每一行提取日期部分,然后将该行附加到相应的文件中。但请注意,如果您遵循这种幼稚的方法,则意味着对于输入文件中的每一行,bash 都必须打开输出文件、执行附加操作并关闭输出文件。如果你有很多行,这可能需要很长时间。对于很长的输入文件,我不会使用 bash 来完成这项任务。
  • @user1934428 我正在尝试为 unix 编写脚本,您能帮忙吗?
  • 糟糕,您忘记发布代码了。 StackOverflow 旨在帮助人们修复他们的代码。这不是免费的编码服务。任何代码都比没有代码好。即使您不知道如何编写它,元代码甚至会展示您认为程序应该如何工作。鉴于您包含的标签,我希望在您的问题中看到一些 bash 代码。
  • @VineetD :发布您的代码并告诉我们您遇到的问题。

标签: bash unix awk scripting


【解决方案1】:

使用 awk:

$ awk '
{
    split($0,a,/[/.]/)                 # split record on chars ./
    f=a[2] "-" a[3] "-" a[4] ".txt"    # make filename 
    print >> f                         # print (appending) to file
    close(f)                           # close the file to preserve fds
}' input.txt

创建的文件:

$ ls
2018-06-01.txt
2018-06-02.txt
2018-06-03.txt

一个文件内容:

$ cat 2018-06-01.txt
/2018/06/01/abc.txt
/2018/06/01/xyz.txt
/2018/06/01/ghi.txt

注意没有错误检查。

【讨论】:

  • 为什么要使用 split 和 array 而不是设置 FS 和使用字段?
  • @EdMorton 是的,几个小时前一定是有道理的。
  • 黄金法则:先喝咖啡,再用键盘... :-)
【解决方案2】:

使用简单的 bash 脚本。

#!/bin/bash
set -e
for i in `cat input.txt`
do
  y=`echo $i|cut -d "/" -f2`
  m=`echo $i|cut -d "/" -f3`
  d=`echo $i|cut -d "/" -f4`
  f_name=`echo "${y}-${m}-${d}.txt"`
  echo $i >>$f_name

done

编辑,作者 Ed Morton(参见下面的 cmets)

只是修复了上面的反模式和错误,但实际上并未对其进行改进,仍然不建议这是一个合理的方法:

#!/bin/env bash
set -e
while read -r i; do
  y=$(echo "$i"|cut -d '/' -f2)
  m=$(echo "$i"|cut -d '/' -f3)
  d=$(echo "$i"|cut -d '/' -f4)
  f_name="${y}-${m}-${d}.txt"
  echo "$i" >>"$f_name"

done < input.txt

【讨论】:

  • 在给定各种输入值的情况下,这会以各种奇怪而奇妙的方式破坏您的输出,而且效率极低。不要这样做。
  • @EdMorton,我认为他只是想了解一下 bash,所以简单的例子会对他有所帮助。只是一个想法
  • 但是你永远不应该这样做,因为它充满了错误(例如未引用的变量)、反模式(例如for i in cat...)和不推荐使用的构造(反引号而不是$(...))加上它很简单无论如何,这样的任务的错误方法,所以它不是一个有用的例子。
  • @Jeff 一旦我完成了,这将是一个完全不同的答案,因为这对于 shell 循环(参见 unix.stackexchange.com/q/169716/133219)和正确的方法(awk 脚本)来说不是一个合适的工作已经发布。告诉你,我会解决这些问题,所以至少你可以看到如果 shell 循环适合这个问题,你应该如何编写它。
【解决方案3】:

您能否也尝试一下,与詹姆斯先生有点不同的方法,我仅在 Input_file(第 2、第 3 和第然后在每一行中关闭它)。还使用/ 作为行的字段分隔符。

awk '
BEGIN{
  FS="/"
  OFS="-"
}
{
  file=$2 OFS $3 OFS $4".txt"
}
prev!=file{
  close(prev)
  prev=file
}
{
  print >> (file)
}'  Input_file

【讨论】:

  • @Vineet D,请您在上面尝试一次并告诉我们。
【解决方案4】:

使用 GNU awk 进行 gensub() 和内部打开文件控制:

awk '{print > gensub("/([^/]+)/([^/]+)/([^/]+)/[^.]+","\\1-\\2-\\3",1)}' file

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    相关资源
    最近更新 更多