以下是我目录中的几个文件。
**$pwd
/opt/offline/**
1 -rw-r--r--. 1 root root 40513 Aug 7 10:02 TN_DAY0OFFER8047_07082014100213_processed
2 -rw-r--r--. 1 root root 32335 Aug 7 10:02 TN_DAY0OFFER8204_07082014100217_processed
3 -rw-r--r--. 1 root root 20126 Aug 7 10:02 TN_DAY0OFFER8047_07082014100221_processed
4 -rw-r--r--. 1 root root 205175 Aug 7 10:02 TN_DAY0OFFER7027_07082014100225_locked
5 -rw-r--r--. 1 root root 15776 Aug 7 10:02 TN_DAY0OFFER7020_07082014100229_locked
6 -rw-r--r--. 1 root root 0 Aug 7 10:02 TN_DAY0OFFER7020_07082014100233_locked
现在第1&第三个文件具有相同的名称(不考虑时间戳),类似于第五个&第6个文件具有相同的名称。 现在我想要获取重复的文件(即第3和第6个)并将其附加到第1个和第2个文件中。分别为5,这样就不会有重复的文件和数据丢失......(最好使用perl或shell)。
答案 0 :(得分:1)
使用Bash 4.0。
#!/bin/bash
error_exit() {
echo "$1" >&2
exit 1
}
[ -n "$BASH_VERSION" ] && [[ BASH_VERSINFO -ge 4 ]] || error_exit "Script requires Bash 4.0."
[[ -z $1 || ! -d $1 ]] && error_exit "Directory not specified or doesn't exist: $1"
pushd "$1" || error_exit "Unable to change directory to $1."
declare -A MAP
shopt -s nullglob
for F in *_*_*_*; do
[[ -f $F ]] || continue
IFS=_ read -ra A B C D __ <<< "$F"
BASE=${MAP["$A|$B|$D"]}
if [[ -n $BASE ]]; then
cat "$F" >> "$BASE"
rm -f -- "$F"
else
MAP["$A|$B|$D"]=$F
fi
done
用法:
bash script.sh dir
注意:如果您不希望删除或更改错误的文件,请先使用复制的文件对其进行测试。
cp -a dir /tmp/dir.copy
bash script.sh /tmp/dir.copy
说到操作文件,shell更合适。它也可以与awk
一起使用,但awk
仍然依赖于/bin/sh
,并且有时候参数的卫生很难或很苛刻。
答案 1 :(得分:1)
这是一个执行您想要的Perl脚本。它在当前目录中查找以“TN”开头的文件,并构建一个数组哈希,将具有相似名称的文件组合在一起。然后它通过哈希并连接文件,删除旧文件。
毋庸置疑,在使用此脚本之前对原始文件进行备份!
use strict;
use warnings;
my %merges;
for my $file (glob "TN*") {
if ($file =~ /(.*)_\d+_(.*)/) {
push @{$merges{"$1$2"}}, "'$file'";
}
}
for (keys %merges) {
my @files = @{$merges{$_}};
my $target = shift @files;
if (@files) {
print "concatenating @files to $target\n";
`cat @files >> $target && rm @files`;
}
}
答案 2 :(得分:1)
使用Perl:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Glob;
my $dir = $ARGV[0];
die "No argument was passed." if not defined $dir;
die "Argument is not a directory: $dir" if not -d $dir;
chdir "$dir" or die "Unable to change directory to $dir.";
my @files = <*_*_*_*>;
my $map = {};
foreach my $f (@files) {
next if not -f $f;
my ($a, $b, $c, $d) = split(/_/, $f);
my $key = "$a|$b|$d";
my $base = $map->{$key};
if (defined $base) {
open(A, '>>', $base) or die "Unable to open file $base for reading.";
open(B, '<', $f) or die "Unable to open file $f for reading.";
while (my $line = <B>) {
print A $line;
}
close(A);
close(B);
unlink $f;
}
$map->{$key} = $f;
}
用法:
perl script.pl dir
答案 3 :(得分:0)
我认为这里有一些锤子破解坚果......
#! /bin/sh -
# Concatenate files sharing a common prefix (before '_').
# The files are concatenated to a file named by the prefix.
curr=XXX
ls *_* | sort | while read fn
do
pfx=`expr $fn : '\([^_]*\).*'`
if test $pfx = $curr; then
# another in this group of files, sharing a prefix
cat $fn >> $pfx
else
# new group of files with prefix $pfx
cp $fn $pfx
curr=$pfx
fi
done
这不是正好你提出的问题,但似乎与你想要的相符(并且它不涉及*shudder*
Perl。)