Preliminary note
This answer introduces commands valid in POSIX-compliant or almost POSIX-compliant operating systems, in particular in Linux or macOS. Commands are not for pure Windows (but I suppose the answer can be adjusted to work in WSL or Cygwin).
Analysis
OK, you have copied some image to a USB drive /dev/sdx
. In general you cannot exactly reverse the process basing solely on the content and properties of the drive because you don't know how many bytes to read. The upper bound is the size of the drive (64 GB in your case), everything else is a guess. The drive contains a stream of bytes and there is no mark saying "stop reading here to get the original image".
By analyzing the partition table (if any) it's possible to take an educative guess. But even then you cannot be sure the original image was not larger (with garbage or non-garbage at the end).
However you want to compare the result to some other image, let's call it the_other_file
. I guess you hope the two images will be identical. To be identical they must be of the same size. This means you know how many bytes to read from /dev/sdx
: the exact number of bytes the_other_file
has. You can get this number by invoking
wc -c /path/to/the_other_file
or
</path/to/the_other_file wc -c
Note the former is a standalone command while the latter requires a shell (to handle <
). From now on I assume you're in a shell.
Copying
If your ultimate goal is to compare then you don't need to copy to a regular file. Read the whole answer before you decide. Still the explicit question is:
How can I recreate an installer iso from a usb […] using dd
?
It seems dd
is the only POSIX way to read an exact number of bytes from a file. The way requires ibs=1
, it can be slow. To read N
bytes:
dd ibs=1 count=N if=/dev/sdx of=image_file
The resulting file is image_file
.
The original image, as an image designed to be written to a block device, most likely was of a size that is multiple of 512 bytes, possibly a multiple of 4096 bytes. You probably can use some bigger ibs
then.
If N
is an exact multiple of some bigger ibs
you want to use then you can use the bigger ibs
with count
adjusted. The number after count=
specifies how many blocks of the size ibs
to read. Notes:
bs
specifies both ibs
and obs
(see man 1 dd
).
- Neither
bs=4m
(from your example) nor bs=4M
belong to the POSIX specification of dd
. The valid suffixes are k
and b
. You may be surprised the specification also allows strings in a form of AxB
. To get 4 MiB use bs=4kx1k
; to get 4 MB use bs=4000000
or bs=4000x1000
etc.
- In general keep in mind
dd
is a cranky tool which is hard to use correctly. There are pitfalls. See this and this.
If N
is not an exact multiple of some bigger ibs
you want to use, it's possible to read the majority of what you want to read with the large ibs
and append the missing part while reading with ibs=1
. This is cumbersome, requires some calculations, still it's technically possible; hardly ever useful though. If you are not limited to POSIX, there are better ways.
GNU dd
supports iflag=count_bytes
that makes count
count bytes regardless of ibs
. Along with iflag=fullblock
it makes dd
a decent tool to read an exact number of bytes. In your case the command could be:
dd bs=4M iflag=fullblock,count_bytes count=N if=/dev/sdx of=image_file
or (to avoid typing N
manually):
dd bs=4M iflag=fullblock,count_bytes count="$(</path/to/the_other_file wc -c)" if=/dev/sdx of=image_file
If I were you I would use head -c
:
head -c "$(</path/to/the_other_file wc -c)" /dev/sdx >image_file
Note wc -c
is portable (specified by POSIX) but head -c
is not (although I believe head
in macOS supports -c
).
Comparing
You can compare directly, without creating any image_file
. The following command is portable:
cmp /dev/sdx /path/to/the_other_file
In your case /dev/sdx
is a device larger than the_other_file
. You will get either a message (to stdout) the files differ, or a message (to stderr) EOF on the_other_file
. In either case the exit status will be 1
. The latter message means the beginning of /dev/sdx
is identical to the_other_file
. This is what you would expect after copying the_other_file
to /dev/sdx
.
If you want to judge by the exit status (useful in scripting) then you need to make sure you're comparing files of equal sizes. This is still possible without creating any image_file
:
head -c "$(</path/to/the_other_file wc -c)" /dev/sdx | cmp - /path/to/the_other_file
(The exit status of a pipeline comes from the last command; here: from cmp
.) Note head -c
is (still :)
) not portable. You can replace it with portable dd …
if needed:
dd ibs=1 count="$(</path/to/the_other_file wc -c)" if=/dev/sdx | cmp - /path/to/the_other_file
Alternatively after creating image_file
as shown above, you can straightforwardly compare image_file
to the_other_file
:
cmp image_file the_other_file
Exit status 0
indicates the files are identical; exit status 1
indicates the files are not identical.
While working interactively you can pay attention to the output instead (I mean stdout + stderr, i.e. all what you normally see in a terminal). Empty output from cmp
indicates the files are identical; non-empty output from cmp
indicates whatever it says. Note dd
(but not head
) prints to stderr even if there was no error. I deliberately wrote "empty output from cmp
", not just "empty output". When in doubt, check the exit status anyway: run echo $?
just after cmp
(or after a pipeline ending with cmp
).