11

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 ?)

  • 2
    See dd and its skip, count, and ibs options. – choroba Sep 19 '17 at 18:33
13

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
  • Does the index counter start from 0 or 1. So I guess if skip is 1 that means that it starts from the 2nd byte. Is that correct? – PiNewbie Sep 19 '17 at 18:57
8

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
  • 3
    You can corrupt a filesystem with head just as easily (or easier), if you're crazy enough to pipe its output to a block device. Of course, you wouldn't do that -- you'd use dd instead, or something else meant for the job. The reason for dd's scary reputation is that it's just robust enough that you can more or less safely use it for intrinsically dangerous tasks like cloning disk images, if you're careful enough. Of course, some people aren't and will mess up their disk -- but the reason for that isn't that they used dd, it's that they were messing with /dev/sda in the first place. – Ilmari Karonen Sep 19 '17 at 22:37
  • Very nice! I didn't know about head -c. – cxw Sep 20 '17 at 12:08
  • 1
    You can only corrupt a filesystem if you're running as root. And if you're root you can corrupt it with practically any utility that writes to files. – Barmar Sep 22 '17 at 22:43
  • @IlmariKaronen Fair enough - I've removed the unnecessary anti-dd FUD. – Digital Trauma Sep 22 '17 at 22:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.