2014-08-29 26 views
4

我有存儲與文件名列表兩個文件:串連每四個文件,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 

因爲我有文件的一個長長的清單,我想自動執行,任何人都可以幫忙。 如果有任何不清楚的地方,請指出。

回答

6

另一種快速的方法來做到這一點不sed

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

迪迪埃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 

優點:這是唯一的一個一行迄今不EVAL任何輸出(| bash),並且不使用臨時文件,並且只使用到處都可以找到的標準工具(cat,xargs,paste)。

+0

我想出了另一種方式在同一時間! :)你的方法雖然可能更簡單。我需要更多地使用'while'循環。 – dshepherd 2014-08-29 12:14:07

+0

謝謝,真棒! – 2014-08-29 12:52:31

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 
1

一個內膽什麼:

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

,您可以通過刪除最後一個管道bash測試的內容將實際產生的命令。

對於FileA每一行,獲得未來三年N,轉換換行符\n爲空格,前置cat,並追加>。然後將每條生成的線-FileB中的一條線合併。將這些命令發送到bash


即使較短sed,在單個更換命令添加cat>

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

另一種方法:你可以使用

cat FileA | xargs -n4 echo 

但是我想不出任何特別優雅的方式來此與來自FILEB輸出文件名結合極易產生四個文件名組。一種可能是做一些字符串處理然後評估它(就像Didier Trosset的回答)。

編輯:明白了!使用GNU平行(類似的類固醇xargs的):

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

在各組的4個參數的parallel命令運行貓並將輸出到臨時文件。它將這些臨時文件的名稱寫入stdout(並且-k表示它們按正確的順序寫出)。

paste將所需的文件名插入流中,然後我們只使用xargs -n 2 mv將臨時文件移動到所需的位置。

我用< tempA而不是cat tempA,因爲它在技術上是best practice

與其他一行相比,優勢(在我看來)是,您不必評估字符串(例如使用bash)。

+2

你也可以在最後使用'paste':cat FileA | xargs -n4 echo cat | paste -d'>' - FileB | bash'。我認爲這是最短的答案:) – 2014-08-29 11:23:49

+0

我真的很想找到一個不涉及評估字符串的單線程,但我無法想象如何去做。我認爲我們需要一些方法將獨立的參數列表傳遞給'xargs',但是你不能... – dshepherd 2014-08-29 11:39:47

+1

明白了!看到我的回答... – 2014-08-29 12:02:18

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少「漂亮」),則前面加上"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. 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 
    

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