【问题标题】:Linux: Using split on limited spaceLinux:在有限空间上使用拆分
【发布时间】:2015-06-16 03:50:35
【问题描述】:

我在一台 linux 机器上有一个巨大的文件。该文件约为 20GB,我的盒子上的空间约为 25GB。我想将文件拆分为 ~100mb 部分。我知道有一个“拆分”命令,但它保留了原始文件。我没有足够的空间来保存原件。关于如何实现这一点的任何想法?如果它们使任务比 bash 更容易,我什至会使用任何节点模块。

【问题讨论】:

  • 您是说不能同时在磁盘上同时保存原始文件和拆分文件吗?这需要一个非常不同的过程(实际上是在分割部分时截断原始文件)。
  • tailtruncate 组合可以工作吗? tail 生成零件,truncate 缩小文件大小;在循环中重复它
  • 你在这里查看过这篇文章吗:superuser.com/questions/617597/…

标签: linux bash file-io


【解决方案1】:

我的尝试:

#! /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

以上假设bash(1),以及stat(1)dd(1)truncate(1)的Linux实现。它应该尽可能快,因为它使用dd(1) 来复制初始文件的块。它还使用bc(1) 来确保20GB 范围内的算术运算不会溢出任何东西。但是,该脚本仅在较小的文件上进行了测试,因此请在针对您的数据运行之前仔细检查它。

【讨论】:

    【解决方案2】:

    您可以在 shell 脚本中使用 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
    

    我用随机文件确认了结果:

    $ 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  -
    

    【讨论】:

    • 两种解决方案都有效。我希望我能接受这两个答案,但只能接受一个。反正我投了你一票。感谢您花时间回答,这对我很有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-13
    • 1970-01-01
    • 1970-01-01
    • 2021-01-23
    • 2014-02-02
    相关资源
    最近更新 更多