连接每四个文件,Linux

时间:2014-08-29 09:46:22

标签: linux bash concatenation

我有两个文件存储文件名列表:

FileA:
GSM1328513
GSM1328514
GSM1328515
GSM1328516
GSM1328545
GSM1328546
GSM1328547
GSM1328548
GSM1328609
GSM1328610
GSM1328611
GSM1328612

and:
FileB:
    Brn
    Hrt
    Lng 

我想要做的是,连接fileA中列出的每四个文件,并将连接文件命名为fileB中列出的文件名: 要手动完成,它看起来像:

cat GSM1328513 GSM1328514 GSM1328515 GSM1328516 > Brn
cat GSM1328545 GSM1328546 GSM1328547 GSM1328548 > Hrt
cat GSM1328609 GSM1328610 GSM1328611 GSM1328612 > Lng

由于我有很长的文件列表,我想自动完成,任何人都可以帮忙。 如果有任何不清楚的地方,请指出。

6 个答案:

答案 0 :(得分:6)

没有sed的另一种快速方法:

cat FileA | while read a ; do read b ; read c ; read d ;
    echo "cat $a $b $c $d > " ; done | paste - FileB | bash

正如Didier Trosset所说,您可以跳过| bash以查看它在执行之前的作用。

其他方法:没有评估的单线程,将@dshepherd解决方案与我的结合:

cat FileA | xargs -n4 echo | paste - FileB | while read a b c d e ; do cat $a $b $c $d > $e ; done

优点:到目前为止,这是唯一一个不评估任何输出(| bash)并且不使用临时文件的内容,只使用在任何地方找到的标准工具(cat,{{ 1}},xargs)。

答案 1 :(得分:2)

以下是执行您要执行的操作的Shell脚本

iter=0
while read filename
do
    stop=`expr \( $iter + 1 \) \* 4`
    iter=`expr $iter + 1`
    files=`head -n $stop fileA | tail -n 4 | tr '\n' ' '`
    cat $files > $filename
done < fileB

答案 2 :(得分:2)

另一种方法:您可以使用

轻松生成包含四个文件名的组
cat FileA | xargs -n4 echo

但是我想不出任何特别优雅的方法将它与FileB的输出文件名结合起来。一种可能性是进行一些字符串操作然后评估它(就像Didier Trosset的答案)。

编辑:搞定了!使用GNU parallel(就像类固醇上的xargs):

parallel < tempA -n4 -k --files cat | paste - tempB | xargs -n 2 mv

parallel命令在每组4个参数上运行cat,并将输出放入临时文件中。它将这些临时文件的名称写入stdout(而-k表示它们以正确的顺序写出)。

paste将所需的文件名插入流中,然后我们只使用xargs -n 2 mv将临时文件移动到所需的位置。

我使用< tempA代替cat tempA,因为从技术上讲best practice

这个(在我看来)优于其他一个衬垫的优点是你没有eval字符串(例如使用bash)。

答案 3 :(得分:2)

使用awk

awk '{ORS=(NR%4?" ":"\n")}1' FileA | awk '{print "cat "$0" > "}' | paste - FileB | bash

或者,使用dshepherd方法进行第一步:

xargs -n4 echo < FileA | awk '{print "cat "$0" >"}' | paste - FileB | bash

我发现这些非常干净,可扩展且符合逻辑。

最简单的方法(虽然方法不太通用,IMO少,#34;漂亮&#34;),每个"cat"分组前置xargs,并附加> paste命令中的分隔符:

 xargs -n4 echo cat < FileA | paste -d ">" - FileB | bash

说明:

  1. 使用awk,将每组四行组成一行。 如果记录编号RN为模4,则与新行"\n"分开,否则为单个空格" "。 这给出了输出:

    $ awk '{ORS=(NR%4?" ":"\n")}1' FileA
    GSM1328513 GSM1328514 GSM1328515 GSM1328516
    GSM1328545 GSM1328546 GSM1328547 GSM1328548
    GSM1328609 GSM1328610 GSM1328611 GSM1328612
    

    根据dshepherd的建议,使用xargs

    可以更轻松地完成此操作
    $ xargs -n4 < FileA
    GSM1328513 GSM1328514 GSM1328515 GSM1328516
    GSM1328545 GSM1328546 GSM1328547 GSM1328548
    GSM1328609 GSM1328610 GSM1328611 GSM1328612
    
  2. 现在,对于这些行中的每一行,前缀为cat并附加>

    $ xargs -n4 < FileA | awk '{print "cat "$0" > "}' 
    cat GSM1328513 GSM1328514 GSM1328515 GSM1328516 > 
    cat GSM1328545 GSM1328546 GSM1328547 GSM1328548 > 
    cat GSM1328609 GSM1328610 GSM1328611 GSM1328612 > 
    
  3. 使用FileBpaste - FileB表示从标准输入获取-来加入$ xargs -n4 < FileA | awk '{print "cat "$0" > "}' | paste - FileB cat GSM1328513 GSM1328514 GSM1328515 GSM1328516 > Brn cat GSM1328545 GSM1328546 GSM1328547 GSM1328548 > Hrt cat GSM1328609 GSM1328610 GSM1328611 GSM1328612 > Lng 中的每一行。

    bash
  4. 通过管道bash执行xargs -n4 < FileA | awk '{print "cat "$0" > "}' | paste - FileB | bash 命令作为{{1}}命令执行每一行:

    {{1}}

答案 4 :(得分:1)

一个班轮:

cat FileA | sed 'N;N;N;s/\n/ /g;s/^/cat /;s/$/ >/;' | paste - FileB | bash

您可以通过删除最后一个管道bash来测试实际生成的命令。

对于FileA的每一行,获取接下来的三个N,将换行\n转换为空格,前置cat,然后追加{{ 1}}。然后将每个生成的行>-中的一行合并。将这些命令发送到FileB


更短的bash,在单个替换命令中添加sedcat

>

答案 5 :(得分:1)

使用bash数组(需要bash 4或更高版本)。我也假设这个数字 fileB中的姓名与fileA中的姓名数相匹配。

readarray -t gsms < FileA
for ((i=0; i<${#gsms[@]}; i+=4)); do
    read fname
    echo "${gsms[@]:i:4}" > "$fname"
done < FileB