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