我有两个文件存储文件名列表:
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
由于我有很长的文件列表,我想自动完成,任何人都可以帮忙。 如果有任何不清楚的地方,请指出。
答案 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
说明:
使用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
现在,对于这些行中的每一行,前缀为cat
并附加>
。
$ xargs -n4 < FileA | awk '{print "cat "$0" > "}'
cat GSM1328513 GSM1328514 GSM1328515 GSM1328516 >
cat GSM1328545 GSM1328546 GSM1328547 GSM1328548 >
cat GSM1328609 GSM1328610 GSM1328611 GSM1328612 >
使用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
中的每一行。
bash
通过管道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
,在单个替换命令中添加sed
和cat
。
>
答案 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