Write n bytes from a file into another in Bash

Hello how can I write n bytes from one file into a new file starting from the k position using Bash?

  • For example if n=60, k=1 and file size=100 then: the 2nd file would consist of from the 1st byte up to the 60th byte and would be 60 bytes in size
  • For example if n=40, k=61 and file size=100 then: the 2nd file would consist of from the 61st byte up to the 100th byte and would be 40 bytes in size

Possibly we are working with binary files not ASCII files, so the concatenation of 2 halves should be identical to the original file!

(Is it possible with dd ?)


Yes. Per the dd man page, you are looking for something like:

dd bs=1 count=60 if=_filename_1_ of=_filename_2_
dd bs=1 skip=60 count=40 if=_filename_1_ of=_filename_2_

where _filename_n_ is replaced with an actual filename.

bs=1 means that count and skip are byte counts. skip is how many to skip; count is how many to copy. Edit byte counts start from 0, not 1. Therefore, to start at the first byte, use skip=0 (or leave skip unspecified).

As a bash function, you could use:

# copy_nk(n, k, infile, outfile)
copy_nk() {
    dd bs=1 count="$1" skip="$2" ${3:+if="$3"} ${4:+of="$4"}
}

and then call it as

copy_nk 60 0 infile.txt outfile.txt

(with k=0 because byte numbers start at zero).

With the ${3:+...}, you can leave off the output file or the input file. E.g.,

cat infile.txt | copy_nk 60 0 > outfile.txt

Here is another approach using head and bash command groups:

{ head -c60 > /dev/null ; head -c40 > output.txt ; } < input.txt

The first head here reads the first 60 bytes from input.txt and sends it to the bit bucket.

Because these head commands are within the command group, the file position within input.txt will be preserved. Thus the second head will read the next 40 bytes (from byte 61 to 100 using 1-based indexing), and write it to output.txt.


In fact this method can be generalized to give split-like functionality, but with the added benefit of being able to specify the length of each output file. Suppose we have a 100 byte file that we want to split into chunks of sizes 7, 50, 23, and the remainder. We could do:

{
    head -c7 > 7bytes.txt
    head -c50 > 50bytes.txt
    head -c23 > 23bytes.txt
    cat > remaining-bytes.txt
} < input.txt