繁体   English   中英

连接每四个文件,Linux

[英]Concatenate every four files, Linux

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

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

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

另一个没有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 | 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 )并且不使用临时文件的单行程序,并且只使用在任何地方找到的标准工具( catxargspaste )。

以下是执行您要执行的操作的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

另一种方法:您可以轻松生成四个文件名组

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因为它是技术上的最佳实践

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

使用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不那么“漂亮”),为每个xargs分组添加"cat" ,并在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所建议的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. 加入这些线,从线FileB ,采用paste - 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 
  4. 通过管道到bash执行这些行中的每一行作为bash命令:

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

一个班轮:

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

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

对于每一行FileA ,获得未来三年N ,转换换行\\n为空格 ,prepend cat ,并追加> 然后合并每个生成的行-使用FileB 将这些命令发送给bash


甚至更短的sed ,在一个替换命令中添加cat>

cat FileA | sed 'N;N;N;s/\n/ /g;s/.*/cat & >/;' | paste - FileB | bash

使用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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM