Lig*_*ght 3 linux bash file-io
我在linux机器上有一个巨大的文件。该文件约为20GB,我的盒子上的空间约为25GB。我想将文件分割成〜100mb的部分。我知道这里有一个“ split”命令,但是保留了原始文件。我没有足够的空间来保存原件。关于如何完成这方面的任何想法?如果它们使任务比bash容易,我什至将使用任何节点模块。
我的尝试:
#! /bin/bash
if [ $# -gt 2 -o $# -lt 1 -o ! -f "$1" ]; then
echo "Usage: ${0##*/} <filename> [<split size in M>]" >&2
exit 1
fi
bsize=${2:-100}
bucket=$( echo $bsize '* 1024 * 1024' | bc )
size=$( stat -c '%s' "$1" )
chunks=$( echo $size / $bucket | bc )
rest=$( echo $size % $bucket | bc )
[ $rest -ne 0 ] && let chunks++
while [ $chunks -gt 0 ]; do
let chunks--
fn=$( printf '%s_%03d.%s' "${1%.*}" $chunks "${1##*.}" )
skip=$(( bsize * chunks ))
dd if="$1" of="$fn" bs=1M skip=${skip} || exit 1
truncate -c -s ${skip}M "$1" || exit 1
done
Run Code Online (Sandbox Code Playgroud)
上述假定bash(1),以及Linux实现stat(1),dd(1)和truncate(1)。它应该尽可能快,因为它用于dd(1)复制初始文件的块。它还用于bc(1)确保20GB范围内的算术运算不会溢出任何内容。但是,该脚本仅在较小的文件上进行了测试,因此在对数据运行之前,请仔细检查该脚本。
您可以在外壳程序脚本中使用tail和truncate将文件拆分到适当的位置,同时销毁原始文件。我们将文件向后拆分,以便可以使用截断。这是一个示例Bash脚本:
#!/bin/bash
if [ -z "$2" ]; then
echo "Usage: insplit.sh <splitsize> <filename>"
exit 1
fi
FILE="$2"
SPLITSIZE="$1"
FILESIZE=`stat -c '%s' $FILE`
BLOCKCOUNT=$(( (FILESIZE+SPLITSIZE-1)/SPLITSIZE ))
echo "Split count: $BLOCKCOUNT"
BLOCKCOUNT=$(($BLOCKCOUNT-1))
while [ $BLOCKCOUNT -ge 0 ]; do
FNAME="$FILE.$BLOCKCOUNT"
echo "writing $FNAME"
OFFSET=$((BLOCKCOUNT * SPLITSIZE))
BLOCKSIZE=$(( $FILESIZE - $OFFSET))
tail -c "$BLOCKSIZE" $FILE > $FNAME
truncate -s $OFFSET $FILE
FILESIZE=$((FILESIZE-BLOCKSIZE))
BLOCKCOUNT=$(( $BLOCKCOUNT-1 ))
done
Run Code Online (Sandbox Code Playgroud)
我用随机文件确认了结果:
$ dd if=/dev/urandom of=largefile bs=512 count=1000
$ md5sum largefile
7ff913b62ef572265661a85f06417746 largefile
$ ./insplit.sh 200000 largefile
Split count: 3
writing largefile.2
writing largefile.1
writing largefile.0
$ cat largefile.0 largefile.1 largefile.2 | md5sum
7ff913b62ef572265661a85f06417746 -
Run Code Online (Sandbox Code Playgroud)