每四个文件连接一次,Linux
我有两个存储有文件名列表的文件:每四个文件连接一次,Linux,linux,bash,concatenation,Linux,Bash,Concatenation,我有两个存储有文件名列表的文件: FileA: GSM1328513 GSM1328514 GSM1328515 GSM1328516 GSM1328545 GSM1328546 GSM1328547 GSM1328548 GSM1328609 GSM1328610 GSM1328611 GSM1328612 and: FileB: Brn Hrt Lng 我要做的是,将文件A中列出的每四个文件连接起来,并将连接的文件命名为文件B中列出的文件名: 要手动执行此操作,
FileA:
GSM1328513
GSM1328514
GSM1328515
GSM1328516
GSM1328545
GSM1328546
GSM1328547
GSM1328548
GSM1328609
GSM1328610
GSM1328611
GSM1328612
and:
FileB:
Brn
Hrt
Lng
我要做的是,将文件A中列出的每四个文件连接起来,并将连接的文件命名为文件B中列出的文件名:
要手动执行此操作,它看起来像:
cat GSM1328513 GSM1328514 GSM1328515 GSM1328516 > Brn
cat GSM1328545 GSM1328546 GSM1328547 GSM1328548 > Hrt
cat GSM1328609 GSM1328610 GSM1328611 GSM1328612 > Lng
因为我有一长串的文件,我想自动完成,有人能帮忙吗。
如果有什么不清楚的地方,请指出。这是执行您想要执行的操作的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
iter=0
读取文件名时
做
stop=`expr\($iter+1\)\*4`
iter=`expr$iter+1`
files=`head-n$stop fileA | tail-n4 | tr'\n''`
cat$files>$filename
完成
一个衬里:
cat FileA | sed 'N;N;N;s/\n/ /g;s/^/cat /;s/$/ >/;' | paste - FileB | bash
您可以通过删除最后一个管道到bash
来测试实际生成的命令
对于FileA
的每一行,获取下三行N
,将换行\N
转换为空格
,在cat
前面加上前缀,然后追加
。然后将生成的每一行-
与文件B
中的一行合并。将这些命令发送到bash
甚至更短的
sed
,在单个replace命令中添加了cat
和
cat FileA | sed 'N;N;N;s/\n/ /g;s/.*/cat & >/;' | paste - FileB | bash
另一种不用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
,查看它在执行之前做了什么
其他方法:一条不带eval的班轮,将@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
,xargs
,粘贴
)。另一种方法:您可以使用
cat FileA | xargs -n4 echo
然而,我想不出任何特别优雅的方式将其与FileB的输出文件名结合起来。一种可能是进行一些字符串操作,然后对其进行求值(如Didier Trosset的答案)
编辑:明白了!使用GNU并行(类似于类固醇上的xargs):
parallel
parallel
命令对每组4个参数运行cat,并将输出放入临时文件中。它将这些临时文件的名称写入标准输出(并且-k
表示它们以正确的顺序写入)
paste
将所需的文件名插入流中,然后我们只需使用xargs-n2 mv
将临时文件移动到所需的位置
我使用了
而不是cat tempA
,因为从技术上讲它很简单
在我看来,与其他单行程序相比,这种方法的优点是不必求值字符串(例如,使用
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
说明:
awk
,将每组四行组成一行。
如果记录编号,RN
为模四,则用新行“\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
粘贴-FileB
(-
意思是从标准输入中获取)将这些行与文件b
中的行连接起来
$ 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
4或更高版本是必需的)
fileB
中的名称数与fileA
中的名称数匹配
readarray -t gsms < FileA
for ((i=0; i<${#gsms[@]}; i+=4)); do
read fname
echo "${gsms[@]:i:4}" > "$fname"
done < FileB
readarray-t gsms
您也可以在末尾使用粘贴:cat FileA | xargs-n4 echo cat | paste-d'>'-FileB | bash
。我认为这是最短的答案:)我真的很想找到一个不涉及字符串求值的单行程序,但我想不出怎么做。我认为我们需要某种方法将独立的参数列表传递给xargs
,但你不能……我同时想出了另一种方法!:)您的方法可能更简单。我需要开始使用,而循环更多。
$ xargs -n4 < FileA | awk '{print "cat "$0" > "}'
cat GSM1328513 GSM1328514 GSM1328515 GSM1328516 >
cat GSM1328545 GSM1328546 GSM1328547 GSM1328548 >
cat GSM1328609 GSM1328610 GSM1328611 GSM1328612 >
$ 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
xargs -n4 < FileA | awk '{print "cat "$0" > "}' | paste - FileB | bash
readarray -t gsms < FileA
for ((i=0; i<${#gsms[@]}; i+=4)); do
read fname
echo "${gsms[@]:i:4}" > "$fname"
done < FileB