鑑於:帶有「特殊」第一行(例如字段名稱)的一個大文本數據文件(例如CSV格式)。如何分割一個文件,並保持每一塊的第一行?
尋求:所述的coreutils split -l
命令,但與從原始文件中的標題行出現在每個所得到的片的開始處的附加要求的等效。
我猜一些split
和head
的混合會做詭計嗎?
鑑於:帶有「特殊」第一行(例如字段名稱)的一個大文本數據文件(例如CSV格式)。如何分割一個文件,並保持每一塊的第一行?
尋求:所述的coreutils split -l
命令,但與從原始文件中的標題行出現在每個所得到的片的開始處的附加要求的等效。
我猜一些split
和head
的混合會做詭計嗎?
這robhruska的腳本清理了一下:
tail -n +2 file.txt | split -l 4 - split_
for file in split_*
do
head -n 1 file.txt > tmp_file
cat $file >> tmp_file
mv -f tmp_file $file
done
我刪除了在他們不必要的地方wc
,cut
,ls
和echo
。我改變了一些文件名,使它們更有意義。我把它分解成多行,只是爲了方便閱讀。
如果你想變得很花哨,你可以使用mktemp
或tempfile
創建一個臨時文件名,而不是使用硬編碼的文件名。
編輯
使用GNU split
有可能做到這一點:
split_filter() { { head -n 1 file.txt; cat; } > "$FILE"; }; export -f split_filter; tail -n +2 file.txt | split --lines=4 --filter=split_filter - split_
爆發的可讀性:
split_filter() { { head -n 1 file.txt; cat; } > "$FILE"; }
export -f split_filter
tail -n +2 file.txt | split --lines=4 --filter=split_filter - split_
當指定--filter
,split
運行命令(功能在這種情況下,必須導出)爲每個輸出文件並設置v在命令的環境中,可變的FILE
到文件名。
過濾器腳本或函數可以對輸出內容甚至文件名進行任何操作。後者的一個例子可能是輸出到變量目錄中的固定文件名:例如> "$FILE/data.dat"
。
我是新手,當談到巴什福,但我能夠調製這個雙命令怪物。我確信有更優雅的解決方案。
$> tail -n +2 file.txt | split -l 4
$> for file in `ls xa*`; do echo "`head -1 file.txt`" > tmp; cat $file >> tmp; mv -f tmp $file; done
這是假設你的輸入文件是file.txt
,你不使用prefix
參數split
,和你在一個目錄中工作,不具有與split
的默認啓動的任何其他文件輸出格式爲xa*
。另外,用你想要的分割線尺寸替換'4'。
我從來不確定直接從其他人的網站複製腳本的規則,但Geekology有一個很好的腳本來執行您想要的操作,並有幾條註釋確認它可以正常工作。一定要做tail
-n
+2
正如註釋底部附近的註釋。
這是一個更穩健的版本丹尼斯威廉姆森的腳本。該腳本創建了大量臨時文件,如果運行不完整,它們仍然處於左右躺臥的狀態將會是一種恥辱。因此,我們添加信號陷阱(請參閱http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html,然後http://tldp.org/LDP/abs/html/debugging.html)並刪除我們的臨時文件;無論如何,這是最佳做法。
trap 'rm split_* tmp_file ; exit 13' SIGINT SIGTERM SIGQUIT
tail -n +2 file.txt | split -l 4 - split_
for file in split_*
do
head -n 1 file.txt > tmp_file
cat $file >> tmp_file
mv -f tmp_file $file
done
用你想要的任何返回碼替換'13'。噢,你應該反正使用mktemp(因爲有些人已經建議了),所以繼續,從trap中刪除'tmp_file'。看到信號手冊頁以獲取更多的信號。
You可以使用[毫克] AWK:
awk 'NR==1{
header=$0;
count=1;
print header > "x_" count;
next
}
!((NR-1) % 100){
count++;
print header > "x_" count;
}
{
print $0 > "x_" count
}' file
100是每個片的行數 它不需要臨時文件,可以在一行內把
Upvoting教給我一些新東西,但是如果我要編寫一個小腳本,我不妨在Perl或Python中執行它:-) – Arkady 2009-09-13 00:50:23
你可以使用新的。 - GNU coreutils split中的過濾功能split = 8.13(2011):
tail -n +2 FILE.in |
split -l 50 - --filter='sh -c "{ head -n1 FILE.in; cat; } > $FILE"'
我喜歡單線版本。只是爲了讓它對bash更通用,我做了:'tail -n +2 FILE.in | split -d --lines 50 - --filter ='bash -c「{head -n1 $ {FILE%。*}; cat;}> $ FILE」'FILE.in.x' – KullDox 2017-05-04 21:30:45
我很喜歡馬可awk的版本,從這個簡單的一行代碼通過在那裏你可以很容易地指定分割比例爲顆粒狀,只要你想:
awk 'NR==1{print $0 > FILENAME ".split1"; print $0 > FILENAME ".split2";} NR>1{if (NR % 10 > 5) print $0 >> FILENAME ".split1"; else print $0 >> FILENAME ".split2"}' file
我喜歡這個解決方案,但是它僅限於兩個拆分文件 – Bas 2016-05-09 09:47:16
如果你喜歡它,那麼它就有upvote功能;)它可以很容易地調整到更多的文件,但是它不像拆分那樣靈活-l – DreamFlasher 2016-05-09 10:06:00
「one liner」... pshh – Pandem1c 2017-01-19 01:12:36
我真的很喜歡Rob和丹尼斯的版本,以至於我想改善它們。
這裏是我的版本:
in_file=$1
awk '{if (NR!=1) {print}}' $in_file | split -d -a 5 -l 100000 - $in_file"_" # Get all lines except the first, split into 100,000 line chunks
for file in $in_file"_"*
do
tmp_file=$(mktemp $in_file.XXXXXX) # Create a safer temp file
head -n 1 $in_file | cat - $file > $tmp_file # Get header from main file, cat that header with split file contents to temp file
mv -f $tmp_file $file # Overwrite non-header containing file with header-containing file
done
差異:
awk
而不是tail
由於awk
具有更好的性能head | cat
線而不是兩行使用GNU並行:
parallel -a bigfile.csv --header : --pipepart 'cat > {#}'
如果你需要在每個部件的運行命令,然後GNU並行可以幫助做到這一點,太:
parallel -a bigfile.csv --header : --pipepart my_program_reading_from_stdin
parallel -a bigfile.csv --header : --pipepart --fifo my_program_reading_from_fifo {}
parallel -a bigfile.csv --header : --pipepart --cat my_program_reading_from_a_file {}
如果您想要將每個CPU內核分成兩部分(例如,24個核心= 48個相等大小的部分):
parallel --block -2 -a bigfile.csv --header : --pipepart my_program_reading_from_stdin
如果要分割成10塊MB:
parallel --block 10M -a bigfile.csv --header : --pipepart my_program_reading_from_stdin
這似乎是合理的,有人要補充一點,作爲一個內置的功能'split' ,不是嗎? – 2009-09-11 16:49:09
對於這種成爲內置的最大因素*可能是您通常通過執行「cat a b c>重建」來重建分割文件。文件中的多餘行意味着正常重建方法不會重現原始文件。 – 2009-09-11 18:23:29
這就是即將推出的(* not *)「'unsplit --remove-header'」工具!但嚴重的是,'split',如果它有一個「repeat-header」選項,仍然應該默認爲它的當前行爲。如果你真的想要它,你只能使用標題。 – 2009-09-11 19:00:31