【问题标题】:Need to pick Latest File From a Dir Using Shell Script需要使用 Shell 脚本从目录中选择最新文件
【发布时间】:2012-11-20 07:27:00
【问题描述】:

我是 Shell 脚本的新手,我需要使用 Shell 脚本从目录中选择最新文件

目录名称:FTPDIR

此目录中的文件将是

APC5502015VP072020121826.csv
APC5502015VP082020122314.csv
APC5502015VP092020121451.csv
CBC5502015VP092020122045.csv
CBC5502015VP102020122045.csv
S5502015VP072020121620.csv
S5502015VP072020122314.csv
S5502015VP092020122045.csv

注意:(需要从每个组中选择一个最新的)- 下面是我执行 shell 脚本后需要得到的输出

APC5502015VP092020121451.csv
CBC5502015VP102020122045.csv
S5502015VP092020122045.csv

例如:在最新的文件 APC5502015VP092020121451.csv 中,没有 092020121451 是日期部分,格式为:MMDDYYYYHHMM,字符串部分是 APC5502015VP(字符串部分的长度不固定)

我需要使用 shell 脚本从目录中选择这三个文件

你能帮我解决这个问题吗?

【问题讨论】:

  • 到目前为止你有什么?你试过什么?
  • 如果您在文件名中使用 YYYYMMDD 而不是 MMDDYYYY,您的生活会轻松很多!设计 ISO 8601 的人完全正确。
  • 日期部分之前的 VP 是否总是那对字符(或者您是否必须从 . 倒数才能找到前缀的结尾?文件名是否包含空格或其他尴尬的角色?
  • 不能说因为在上面的目录列表中它是 VP Before Date 部分但它可以是任何长度的字符串但格式将 ba as

标签: bash shell ksh


【解决方案1】:

在 bash 中安全地执行此操作将是非常有问题的。正如 Jonathan 所说,空格或换行符等“特殊”字符可能会破坏您的脚本。

如果我们可以假设不会有这些,那么我们可以在 bash 中完成大部分工作,而无需涉及其他工具。

# Make an associative array to record types, in the second loop...
declare -A a

for file in *.csv; do
    # First, we convert the filenames into something that can be sorted.
    # The next three lines account for your "unknown length" in the first part
    # of the filename. We assume the date+time is the 12 chars before ".csv".
    new="$(rev <<<"$file")"
    new="${new:4:12}"
    new="$(rev <<<"$new")"
    new="${new:4:4}${new:0:2}${new:2:2}${new:8:4}"
    len=$(( ${#file} - 16 ))
    echo "$new ${file:0:$len} $file"
done | sort | while read date type file; do
    # Next, we print only the first of each "type"...
    if [[ ${a[$type]} -eq 0 ]]; then
        a[$type]=1
        echo "$file"
    fi
    # And stop once we have collected three types.
    if [[ ${#a[*]} -ge 3 ]]; then
        break
    fi
done

正如我所说,这不处理文件名中的换行符。

还要注意,这使用了revsort,它们不是内置于 bash 中的。 rev 部分可以在内部完成,使用更多代码,可能使它们执行得更快,但您只会在非常极端的情况下看到差异。对于 sort,我们无能为力,因为 bash 中没有内置函数。

【讨论】:

  • 为什么只选择每个组的前 3 个字符?该组不是日期左侧的整个字符串吗?
  • @Graham - 嗯,好点; OP并没有真正定义他所说的“组”是什么意思,所以我想我只是编造了。重新阅读后,它似乎应该是整个左侧,在日期之前,正如您所建议的那样。我已经更新了我的答案;注意添加$len
【解决方案2】:

这个 Perl 脚本适用于给定的数据。毫无疑问,它可以改进。

#!/usr/bin/env perl
use strict;
use warnings;

my %bases;

while (<>)
{
    chomp;
    my $name = $_;
    my($prefix, $mmdd, $yyyy, $hhmm) = ($name =~ m/(.*)(\d{4})(\d{4})(\d{4})\.csv/);
    #print "$name = $prefix $yyyy $mmdd $hhmm\n";
    my $stamp = "$yyyy$mmdd$hhmm";
    if (!exists($bases{$prefix}) || ($stamp > $bases{$prefix}->{stamp}))
    {
        $bases{$prefix} = { name => $name, stamp => $stamp };
    }
}

foreach my $prefix (sort keys %bases)
{
    print "$bases{$prefix}->{name}\n";
}

输出:

APC5502015VP092020121451.csv
CBC5502015VP102020122045.csv
S5502015VP092020122045.csv

【讨论】:

    【解决方案3】:

    这是 awk 解决方案:

    cd FTPDIR
    ls -1|awk -F"VP" '{split($2,a,".");if(a[1]>b[$1]){b[$1]=$2}}END{for(i in b)print i"VP"b[i]}'
    

    以下测试:

    > cat temp
    APC5502015VP072020121826.csv
    APC5502015VP082020122314.csv
    APC5502015VP092020121451.csv
    CBC5502015VP092020122045.csv
    CBC5502015VP102020122045.csv
    S5502015VP072020121620.csv
    S5502015VP072020122314.csv
    S5502015VP092020122045.csv
    > awk -F"VP" '{split($2,a,".");if(a[1]>b[$1]){b[$1]=$2}}END{for(i in b)print i"VP"b[i]}' temp
    CBC5502015VP102020122045.csv
    S5502015VP092020122045.csv
    APC5502015VP092020121451.csv
    

    【讨论】:

    • 虽然这适用于所示的输入样本,但parsing LS 通常是不好的做法。
    • 我认为这个解决方案不能只显示每个“类型”的第一项。
    猜你喜欢
    • 1970-01-01
    • 2021-09-06
    • 2013-01-12
    • 2021-01-25
    • 2017-01-19
    • 2022-10-23
    • 2012-10-13
    • 2017-08-09
    • 1970-01-01
    相关资源
    最近更新 更多