合并多个文件,保留unix中的原始序列

时间:2015-03-30 07:43:20

标签: linux bash shell unix command-line

我在目录中有多个(超过100个)文本文件,例如

files_1_100.txt
files_101_200.txt

该文件的内容是一些变量的名称,如files_1_100.txt包含一些介于1到100之间的变量名称

"var.2"
"var.5"
"var.15"

同样files_201_300.txt包含101到200之间的一些变量

"var.203"
"var.227"
"var.285"

files_1001_1100.txt

"var.1010"
"var.1006"
"var.1025"

我可以使用命令

合并它们
cat files_*00.txt > ../all_files.txt

但是,文件的内容不会跟随父文件中的内容。例如all_files.txt显示

"var.1010"
"var.1006"
"var.1025"
"var.1"
"var.5"
"var.15"
"var.203"
"var.227"
"var.285"

那么,我如何确保files_1_100.txt的内容首先出现,然后是files_201_300.txt然后files_1001_1100.txt,以便all_files.txt的内容

"var.1"
"var.5"
"var.15"
"var.203"
"var.227"
"var.285"
"var.1010"
"var.1006"
"var.1025"

6 个答案:

答案 0 :(得分:2)

让我尝试一下,但我认为这会奏效:

ls file*.txt | sort -n -t _ -k2 -k3 | xargs cat

我们的想法是获取文件列表并对其进行排序,然后将它们传递给cat命令。

排序使用了几个选项:

  • -n - 使用数字排序而不是字母
  • -t _ - 使用下划线字符
  • 将输入(文件名)分成字段
  • -k2 -k3 - 首先按第2个字段排序,然后按第3个字段排序(2个数字)

您已经说过您的文件名为file_1_100.txt,file_101_201.txt等。如果这意味着(似乎表明)第一个数字“块”始终是唯一的,那么您可以放弃{{1标志。只有当您最终使用file_100_2.txt和file_100_10.txt时才需要该标志,您必须查看第二个数字“块”以确定首选顺序。

根据您使用的文件数量,您可能会发现指定glob(文件* .txt)可能会破坏shell并导致该行的错误太长。如果是这种情况,你可以这样做:

-k3

答案 1 :(得分:2)

您可以使用printf sort并将其传递给xargs cat

printf "%s\0" f*txt | sort -z -t_ -nk2 | xargs -0 cat > ../all_files.txt

请注意,整个管道正在处理NULL终止的文件名,因此确保此命令甚至可以使用空格/换行符等文件名。

答案 2 :(得分:1)

如果您的文件名没有任何特殊字符或空格,那么其他答案应该是简单的解决方案。 否则,请尝试这种基于rename的方法:

$ ls files_*.txt
files_101_200.txt  files_1_100.txt

$ rename  's/files_([0-9]*)_([0-9]*)/files_000$1_000$2/;s/files_0*([0-9]{3})_0*([0-9]{3})/files_$1_$2/' files_*.txt

$ ls files_*.txt
files_100_100.txt  files_101_200.txt

$ cat files_*.txt > outputfile.txt

$ rename 's/files_0*([0-9]*)_0*([0-9]*)/files_$1_$2/' files_*.txt

答案 3 :(得分:0)

cat file_*的默认排序行为是按字母顺序排列的,而不是数字。

按数字顺序列出它们然后cat每一个,将输出附加到某个文件。

ls -1| sort -n |xargs -i cat {} >> file.out

答案 4 :(得分:0)

您可以尝试使用for循环并逐个添加文件(-v在数字未填零时正确排序文件)

for i in $(ls -v files_*.txt)
do
    cat $i >> ../all_files.txt
done

或单线更方便:

for i in $(ls -v files_*.txt) ; do cat $i >> ../all_files.txt ; done

答案 5 :(得分:0)

您也可以通过拆分和排序ARGV

来使用Awk执行此操作
awk 'BEGIN {
    for(i=1; i<=ARGC-1; i++) {
        if(i > 1) {
            j=i-1
            split(ARGV[i], curr, "_")
            split(ARGV[j], last, "_")
            if (curr[2] < last[2]) {
                tmp=ARGV[i]
                ARGV[i]=ARGV[j]
                ARGV[j]=tmp
            }
        }
    }
}1' files_*00.txt