使用特定命名模式(unix)连接文件

时间:2017-01-13 16:55:37

标签: loops unix concatenation sh string-matching

我想连接遵循特定名称模式的文件,即我有许多文件,如:

nameX_4_1.txt
nameX_983_2.txt
nameX_5_1.txt
nameX_2_2.txt
nameY_7_1.txt
nameY_4_2.txt
nameY_8_1.txt
nameY_3_2.txt
nameY_9_1.txt
nameY_6_2.txt
.
.
.

...我想要连接具有相同"名称的文件?"和相同的最后一个数字(1或2),即从上面的示例文件到连接

"nameX_4_1.txt" and "nameX_5_1.txt"  
"nameX_983_2.txt" and "nameX_2_2.txt"
"nameY_7_1.txt" and "nameY_8_1.txt" and "nameY_9_1.txt"
"nameY_4_2.txt" and "nameY_3_2.txt" and "nameY_6_2.txt"
.
.
.

我首先尝试编写如下脚本:

for f1 in *_?_1.txt
do
f2="${f1%%_?_1.txt}_?_2.txt"
.
.
.

...但我重新(作为一个完整的unix菜鸟)这不是如何获取其他匹配文件的名称的方式,因此所选名称的文件可以循环连接... 我会感谢任何提示(优先使用unix命令但我实际上打开了任何其他解决方案)。谢谢!

4 个答案:

答案 0 :(得分:0)

这是编辑!

首先,对不起之前的错误。我不知道最近有什么东西进入了我。

其次,问题没有说明你想如何连接文件。

如果用Unix标记它你想在shell中做(例如Bash),那么,这将得到你想要的东西:

#! /bin/bash

for file in $(ls ./name*1.txt)
do
    echo $file
done

这将打印出所有文件(每行一个),通过通配符过滤(在名称中使用'*')。 您将不得不使用带有大量管道的read命令或cat来连接名称将在$ file变量中的文件的内容。

如果你有很多文件,这将有点不实用。它仍然有效,但对你的系统很粗鲁。

因此,我建议您使用一些真正的脚本语言在一个过程中实现您想要的功能。 这是Python中的完整示例:

#! /usr/bin/env python
import glob

namepattern = "./name*1.txt"
outputfile = "./output.txt"
whole_text = ""
for x in glob.iglob(namepattern):
    f = open(x, "r")
    whole_text += "\n"+f.read()
    f.close()
f = open(outputfile, "w")
f.write(whole_text)
f.close()

如果要确保在连接之前对文件进行排序,请将sorted()添加到for循环:

for x in sorted(glob.iglob(...)): ...

这只会连接一组由namepattern变量指定的文件。所以你必须运行这个脚本几次。关于如何对它们进行分组的一个想法由hansaplast提供。

答案 1 :(得分:0)

当你对任何编程语言开放时,这是一个python解决方案:

import os
from collections import defaultdict

buckets = defaultdict(list)

for filename in os.listdir('files/'):
    parts = filename.split('.')[0]('_')
    # group by string before first _ and number after last _
    # "nameX_4_1.txt" becomes ("nameX", "1")
    key = (parts[0], parts[-1]) 
    buckets[key].append(filename)

# files are now grouped, output them (order is not predictable)
for key,value in buckets.items():
    print(", ".join(value))

示例会话:

$ ls files/
nameX_2_2.txt   nameX_5_1.txt   nameY_3_2.txt   nameY_6_2.txt   nameY_8_1.txt
nameX_4_1.txt   nameX_983_2.txt nameY_4_2.txt   nameY_7_1.txt   nameY_9_1.txt

$ python script.py
nameX_2_2.txt, nameX_983_2.txt
nameY_3_2.txt, nameY_4_2.txt, nameY_6_2.txt
nameY_7_1.txt, nameY_8_1.txt, nameY_9_1.txt
nameX_4_1.txt, nameX_5_1.txt

python程序希望文件位于files/中,因此您需要将其更改为实际目录。

如果您想了解更多关于python程序的功能或者您是否遗漏任何功能,请发表评论。

答案 2 :(得分:0)

作为一个起点,你可以尝试这个(bash):

for xy in X Y; do 
  for s12 in 1 2; do 
    echo "   $xy --- $s12"
    for file in $(ls name${xy}_*_$s12.txt); do
      echo "file $file"
    done
  done
done

请注意第一个echo行:它在每组文件之前打印。您可以选择(准备)写入临时文件,或者构建稍后要执行的命令,而不是此echo。对于临时文件,您可以使用echo file $file代替cat $file >> my_temporary_file,或类似的内容。

答案 3 :(得分:0)

问题看起来有点毛茸茸,所以我可能使用perl,而不是shell(警告,未经测试的代码):

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

my %groups;

for my $file (glob '*_*_[12].txt') {
    my $key = $file;
    $key =~ s/_[^_]*(?=_\d\.txt\z)/_X/ or die "No match for $key";
    push @{$groups{$key}}, $file;
}

for my $group (values %groups) {
    print "@$group\n";
}

我们的想法是遍历匹配*_*_[12].txt的所有文件,并计算每个名称的规范化密钥;例如foobar_123_1.txt将成为foobar_X_1.txt(我们会使用X替换最后两个下划线之间的部分。)

这样,您要连接的所有文件都在同一个键下组合在一起。最后,我们简单地遍历所有组并输出每个组中的文件名(用空格分隔),然后是换行符。