{
    "mode": "man",
    "parameter": "sg_compare_and_write",
    "section": "8",
    "url": "https://www.chedong.com/phpMan.php/man/sg_compare_and_write/8/json",
    "generated": "2026-06-14T13:43:59Z",
    "synopsis": "sgcompareandwrite  [--dpo]  [--fua]  [--fuanv]  [--grpnum=GN] [--help] --in=IF [--inw=WF]\n--lba=LBA  [--num=NUM]  [--quiet]  [--timeout=TO]  [--verbose]  [--version]  [--wrprotect=WP]\n[--xferlen=LEN] DEVICE",
    "sections": {
        "NAME": {
            "content": "sgcompareandwrite - send the SCSI COMPARE AND WRITE command\n",
            "subsections": []
        },
        "SYNOPSIS": {
            "content": "sgcompareandwrite  [--dpo]  [--fua]  [--fuanv]  [--grpnum=GN] [--help] --in=IF [--inw=WF]\n--lba=LBA  [--num=NUM]  [--quiet]  [--timeout=TO]  [--verbose]  [--version]  [--wrprotect=WP]\n[--xferlen=LEN] DEVICE\n",
            "subsections": []
        },
        "DESCRIPTION": {
            "content": "Send  the SCSI COMPARE AND WRITE command to DEVICE. This utility fetches a compare buffer and\na write buffer from either one or two files. If the --inw=WF option is given then the compare\nbuffer  is  fetched  from the file indicated by the --in=IF while the write buffer is fetched\nfrom the file indicated by the --inw=WF. If the --inw=WF option is not given  then  the  con‐\ncatenated  compare  and  write buffers are fetched from the file indicated by the --in=IF op‐\ntion.\n\nThose buffers are expected to each contain NUM blocks of data. The compare starts at  logical\nblock address LBA on the DEVICE and if the comparison fails (i.e. the provided compare buffer\ndoes not equal the data at LBA on the DEVICE) then the COMPARE  AND  WRITE  command  finishes\nwith  a sense key of MISCOMPARE. In this case this utility will complete and set an exit sta‐\ntus of 14 (which happens to be the sense key value of MISCOMPARE).\n\nIf the comparison succeeds then the provided write buffer is stored starting at LBA  for  NUM\nblocks on the DEVICE.\n\nThe  actual  number of bytes transferred in the data-out buffer of the COMPARE AND WRITE com‐\nmand may need to be given by the user with the --xferlen=LEN option. LEN defaults to (2 * NUM\n*  512)  which is 1024 for the default NUM of 1. If the block size is other than 512 then the\nuser will need to use --xferlen=LEN option.  If protection information is given (indicated by\na  value of WP other than 0 (the default)) then for a NUM of 1 LEN should be 1040 . Note that\nthe SCSI READ CAPACITY command is not performed by this utility  (e.g.   to  find  the  block\nsize).\n\nThe  T10  definition of the SCSI COMPARE AND WRITE command requires that the DEVICE implement\nthe compare and optional write as an uninterrupted series of actions. Depending on some other\nDEVICE settings a verify operation may occur prior to the compare.\n\nWhen  a  mismatch  occurs between the compare buffer and the blocks starting at LBA read from\nthe DEVICE the sense buffer containing the MISCOMPARE sense key causes several messages to be\nsent  to stderr (including the offset of the first byte mismatch). To suppress these messages\nuse the --quiet option. With or without the --quiet option the exit status will be set to 14.\n\nThis command is defined in SBC-3 whose most recent revision is 36. SBC-3 and other SCSI docu‐\nments can be found at http://www.t10.org .\n",
            "subsections": []
        },
        "OPTIONS": {
            "content": "Arguments  to long options are mandatory for short options as well.  The options are arranged\nin alphabetical order based on the long option name.\n",
            "subsections": [
                {
                    "name": "-d --dpo",
                    "content": "Set the DPO bit in the COMPARE AND WRITE CDB\n",
                    "flag": "-d",
                    "long": "--dpo"
                },
                {
                    "name": "-f --fua",
                    "content": "Set the FUA bit in the COMPARE AND WRITE CDB\n",
                    "flag": "-f",
                    "long": "--fua"
                },
                {
                    "name": "-F --fua",
                    "content": "Set the FUANV bit in the COMPARE AND WRITE CDB. This bit was removed in  SBC-3  revi‐\nsion 35d and its position marked as \"reserved\".\n",
                    "flag": "-F",
                    "long": "--fua"
                },
                {
                    "name": "-g --grpnum",
                    "content": "where  GN is the value to be placed in the group number field in the COMPARE AND WRITE\nCDB.\n",
                    "flag": "-g",
                    "long": "--grpnum"
                },
                {
                    "name": "-h --help",
                    "content": "output the usage message then exit.\n",
                    "flag": "-h",
                    "long": "--help"
                },
                {
                    "name": "-i --in",
                    "content": "read data (binary) from file named IF. This will either be the  combined  compare  and\nwrite buffers (when the --inw=WF option is not given) or just the compare buffer (when\nthe --inw=WF option is given). If IF is '-' then stdin (e.g. a pipe) is read.\n",
                    "flag": "-i",
                    "long": "--in"
                },
                {
                    "name": "-C --inc",
                    "content": "The same as the --in option.\n",
                    "flag": "-C",
                    "long": "--inc"
                },
                {
                    "name": "-D --inw",
                    "content": "read data (binary) from file named WF. This will the write buffer that will become the\nsecond  half of the data-out buffer sent to the DEVICE associated with the COMPARE AND\nWRITE command. Note that when this option is given then the  --in=IF  is  expected  to\nhold the associated compare buffer.\n",
                    "flag": "-D",
                    "long": "--inw"
                },
                {
                    "name": "-l --lba",
                    "content": "where LBA is the logical block address to start the COMPARE AND WRITE command. Assumed\nto be in decimal unless prefixed with '0x' or has a trailing 'h'.\n",
                    "flag": "-l",
                    "long": "--lba"
                },
                {
                    "name": "-n --num",
                    "content": "where NUM is the number of blocks, starting at LBA, to read and compare with the  ver‐\nify  instance. And given a match, the NUM of blocks to write starting LBA. The default\nvalue for NUM is 1.\n",
                    "flag": "-n",
                    "long": "--num"
                },
                {
                    "name": "-q --quiet",
                    "content": "suppress the sense buffer messages associated with a MISCOMPARE sense key  that  would\notherwise  be  sent  to stderr. Still set the exit status to 14 which is the sense key\nvalue indicating a MISCOMPARE.\n",
                    "flag": "-q",
                    "long": "--quiet"
                },
                {
                    "name": "-t --timeout",
                    "content": "where TO is the command timeout value in seconds. The default value is 60 seconds.  If\nNUM is large (or zero) a WRITE SAME command may require considerably more time than 60\nseconds to complete.\n",
                    "flag": "-t",
                    "long": "--timeout"
                },
                {
                    "name": "-v --verbose",
                    "content": "increase the degree of verbosity (debug messages).\n",
                    "flag": "-v",
                    "long": "--verbose"
                },
                {
                    "name": "-V --version",
                    "content": "output version string then exit.\n",
                    "flag": "-V",
                    "long": "--version"
                },
                {
                    "name": "-w --wrprotect",
                    "content": "set the WRPROTECT field in the cdb to WP. The default value is 0 which implies no pro‐\ntection information is sent (along with the user data) by this utility.\n",
                    "flag": "-w",
                    "long": "--wrprotect"
                },
                {
                    "name": "-x --xferlen",
                    "content": "where LEN is the data out buffer length in byte. It defaults to (2 * NUM * 512) bytes.\nIf the DEVICE block size is other than 512 bytes or WP  is  non-zero  (implying  addi‐\ntional  protection information) then this default will be incorrect; the use must sup‐\nply the correct value for LEN\n",
                    "flag": "-x",
                    "long": "--xferlen"
                }
            ]
        },
        "NOTES": {
            "content": "Various numeric arguments (e.g. LBA) may include multiplicative suffixes or be given in hexa‐\ndecimal. See the \"NUMERIC ARGUMENTS\" section in the sg3utils(8) man page.\n",
            "subsections": []
        },
        "EXAMPLES": {
            "content": "Before  overwriting  the  first  two blocks of whatever (SCSI) storage device that is chosen,\ntake a small backup. The logical block size is assumed to be  512  bytes.  Take  a  copy  (in\nbackup01.bin) of the first two blocks::\n\n# sgdd if=/dev/sg1 bs=512 of=backup01.bin count=2\n2+0 records in\n2+0 records out\n\nWARNING:  if  /dev/sg1  corresponds  to a disk on your system that contains currently mounted\nfile systems, do not continue. If you can, unmount all file systems on that disk.  If  that\nis not possible, use another disk with no mounted file systems on it. In Linux the scsidebug\ndriver is a good candidate for experimentation.\n\nNow fill the first block with 0xff bytes:\n\n# sgdd iflag=ff bs=512 of=/dev/sg1 count=1\n1+0 records in\n1+0 records out\n\nand the second block with 0x0 bytes:\n\n# sgdd iflag=00 bs=512 seek=1 of=/dev/sg1 count=1\n1+0 records in\n1+0 records out\n\nNow copy those two blocks into a file:\n\n# sgdd if=/dev/sg1 bs=512 of=ff00.bin count=2\n2+0 records in\n2+0 records out\n\nNow we can do a compare and write command. It is told to compare the first block (i.e. LBA 0)\nwith  the  first  block in the given file (i.e. ff00.bin).  If they are equal (they should be\nboth full of 0xff bytes). Since the compare succeeds, it  will  write  the  second  block  in\nff00.bin over LBA 0:\n\n# sgcompareandwrite --in=ff00.bin --lba=0 --num=1 /dev/sg1\n\n\nNo news is good news. Now if we do that command again:\n\n# sgcompareandwrite --in=ff00.bin --lba=0 --num=1 /dev/sg1\nMiscompare at byte offset: 0 [0x0]\nsgcompareandwrite failed: Miscompare\n\nThis is expected. The first sgcompareandwrite ended up writing 0x0 bytes over LBA 0x0. The\nsecond sgcompareandwrite command compares LBA 0x0 with 0xff bytes  and  fails  immediately\n(i.e. at byte offset: 0). Now we will overwrite the first 3 bytes of ff00.bin with 0x0:\n\n# sgdd bs=1 iflag=00 of=ff00.bin count=3\n3+0 records in\n3+0 records out\n\nNotice the 'bs=1' operand. The dd utility (and thus sgdd) is very useful for doing small bi‐\nnary edits on a file. Now if we do that sgcompareandwrite again, it still fails but with a\nsmall difference:\n\n# sgcompareandwrite --in=ff00.bin --lba=0 --num=1 /dev/sg1\nMiscompare at byte offset: 3 [0x3]\nsgcompareandwrite failed: Miscompare\n\nSo the bytes at offset 0, 1, and 2 compared equal but not the byte at offset 3. The SCSI COM‐\nPARE AND WRITE will stop on the first micompared byte.\n",
            "subsections": []
        },
        "EXIT STATUS": {
            "content": "The exit status of sgcompareandwrite is 0 when it is successful. If the compare step fails\nthen  the  exit status is 14. For other exit status values see the EXIT STATUS section in the\nsg3utils(8) man page.\n\nEarlier versions of this utility set an exit status of 98 when there was a MISCOMPARE.\n",
            "subsections": []
        },
        "AUTHORS": {
            "content": "Written by Shahar Salzman. Maintained by Douglas Gilbert. Additions by Eric Seppanen.\n",
            "subsections": []
        },
        "REPORTING BUGS": {
            "content": "Report bugs to shahar.salzman@kaminario.com or dgilbert@interlog.com\n",
            "subsections": []
        },
        "COPYRIGHT": {
            "content": "Copyright © 2012-2020 Kaminario Technologies LTD\nRedistribution and use in source and binary forms, with or without modification, are  permit‐\nted provided that the following conditions are met:\n*  Redistributions of source code must retain the above copyright notice, this list of condi‐\ntions and the following disclaimer.\n* Redistributions in binary form must reproduce the above copyright notice, this list of con‐\nditions  and  the  following  disclaimer in the documentation and/or other materials provided\nwith the distribution.\n* Neither the name of the <organization> nor the names of its contributors may be used to en‐\ndorse  or  promote products derived from this software without specific prior written permis‐\nsion.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND  ANY  EXPRESS\nOR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABIL‐\nITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  SHALL  Kaminario  Tech‐\nnologies  LTD  BE  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSE‐\nQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING  IN  ANY  WAY  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n\n",
            "subsections": []
        },
        "SEE ALSO": {
            "content": "sgxcopy, sgreceivecopyresults(sg3utils)\n\n\n\nsg3utils-1.46                              November 2020                       COMPARE AND WRITE(8)",
            "subsections": []
        }
    },
    "summary": "sgcompareandwrite - send the SCSI COMPARE AND WRITE command",
    "flags": [
        {
            "flag": "-d",
            "long": "--dpo",
            "arg": null,
            "description": "Set the DPO bit in the COMPARE AND WRITE CDB"
        },
        {
            "flag": "-f",
            "long": "--fua",
            "arg": null,
            "description": "Set the FUA bit in the COMPARE AND WRITE CDB"
        },
        {
            "flag": "-F",
            "long": "--fua",
            "arg": null,
            "description": "Set the FUANV bit in the COMPARE AND WRITE CDB. This bit was removed in SBC-3 revi‐ sion 35d and its position marked as \"reserved\"."
        },
        {
            "flag": "-g",
            "long": "--grpnum",
            "arg": null,
            "description": "where GN is the value to be placed in the group number field in the COMPARE AND WRITE CDB."
        },
        {
            "flag": "-h",
            "long": "--help",
            "arg": null,
            "description": "output the usage message then exit."
        },
        {
            "flag": "-i",
            "long": "--in",
            "arg": null,
            "description": "read data (binary) from file named IF. This will either be the combined compare and write buffers (when the --inw=WF option is not given) or just the compare buffer (when the --inw=WF option is given). If IF is '-' then stdin (e.g. a pipe) is read."
        },
        {
            "flag": "-C",
            "long": "--inc",
            "arg": null,
            "description": "The same as the --in option."
        },
        {
            "flag": "-D",
            "long": "--inw",
            "arg": null,
            "description": "read data (binary) from file named WF. This will the write buffer that will become the second half of the data-out buffer sent to the DEVICE associated with the COMPARE AND WRITE command. Note that when this option is given then the --in=IF is expected to hold the associated compare buffer."
        },
        {
            "flag": "-l",
            "long": "--lba",
            "arg": null,
            "description": "where LBA is the logical block address to start the COMPARE AND WRITE command. Assumed to be in decimal unless prefixed with '0x' or has a trailing 'h'."
        },
        {
            "flag": "-n",
            "long": "--num",
            "arg": null,
            "description": "where NUM is the number of blocks, starting at LBA, to read and compare with the ver‐ ify instance. And given a match, the NUM of blocks to write starting LBA. The default value for NUM is 1."
        },
        {
            "flag": "-q",
            "long": "--quiet",
            "arg": null,
            "description": "suppress the sense buffer messages associated with a MISCOMPARE sense key that would otherwise be sent to stderr. Still set the exit status to 14 which is the sense key value indicating a MISCOMPARE."
        },
        {
            "flag": "-t",
            "long": "--timeout",
            "arg": null,
            "description": "where TO is the command timeout value in seconds. The default value is 60 seconds. If NUM is large (or zero) a WRITE SAME command may require considerably more time than 60 seconds to complete."
        },
        {
            "flag": "-v",
            "long": "--verbose",
            "arg": null,
            "description": "increase the degree of verbosity (debug messages)."
        },
        {
            "flag": "-V",
            "long": "--version",
            "arg": null,
            "description": "output version string then exit."
        },
        {
            "flag": "-w",
            "long": "--wrprotect",
            "arg": null,
            "description": "set the WRPROTECT field in the cdb to WP. The default value is 0 which implies no pro‐ tection information is sent (along with the user data) by this utility."
        },
        {
            "flag": "-x",
            "long": "--xferlen",
            "arg": null,
            "description": "where LEN is the data out buffer length in byte. It defaults to (2 * NUM * 512) bytes. If the DEVICE block size is other than 512 bytes or WP is non-zero (implying addi‐ tional protection information) then this default will be incorrect; the use must sup‐ ply the correct value for LEN"
        }
    ],
    "examples": [
        "Before  overwriting  the  first  two blocks of whatever (SCSI) storage device that is chosen,",
        "take a small backup. The logical block size is assumed to be  512  bytes.  Take  a  copy  (in",
        "backup01.bin) of the first two blocks::",
        "# sgdd if=/dev/sg1 bs=512 of=backup01.bin count=2",
        "2+0 records in",
        "2+0 records out",
        "WARNING:  if  /dev/sg1  corresponds  to a disk on your system that contains currently mounted",
        "file systems, do not continue. If you can, unmount all file systems on that disk.  If  that",
        "is not possible, use another disk with no mounted file systems on it. In Linux the scsidebug",
        "driver is a good candidate for experimentation.",
        "Now fill the first block with 0xff bytes:",
        "# sgdd iflag=ff bs=512 of=/dev/sg1 count=1",
        "1+0 records in",
        "1+0 records out",
        "and the second block with 0x0 bytes:",
        "# sgdd iflag=00 bs=512 seek=1 of=/dev/sg1 count=1",
        "1+0 records in",
        "1+0 records out",
        "Now copy those two blocks into a file:",
        "# sgdd if=/dev/sg1 bs=512 of=ff00.bin count=2",
        "2+0 records in",
        "2+0 records out",
        "Now we can do a compare and write command. It is told to compare the first block (i.e. LBA 0)",
        "with  the  first  block in the given file (i.e. ff00.bin).  If they are equal (they should be",
        "both full of 0xff bytes). Since the compare succeeds, it  will  write  the  second  block  in",
        "ff00.bin over LBA 0:",
        "# sgcompareandwrite --in=ff00.bin --lba=0 --num=1 /dev/sg1",
        "No news is good news. Now if we do that command again:",
        "# sgcompareandwrite --in=ff00.bin --lba=0 --num=1 /dev/sg1",
        "Miscompare at byte offset: 0 [0x0]",
        "sgcompareandwrite failed: Miscompare",
        "This is expected. The first sgcompareandwrite ended up writing 0x0 bytes over LBA 0x0. The",
        "second sgcompareandwrite command compares LBA 0x0 with 0xff bytes  and  fails  immediately",
        "(i.e. at byte offset: 0). Now we will overwrite the first 3 bytes of ff00.bin with 0x0:",
        "# sgdd bs=1 iflag=00 of=ff00.bin count=3",
        "3+0 records in",
        "3+0 records out",
        "Notice the 'bs=1' operand. The dd utility (and thus sgdd) is very useful for doing small bi‐",
        "nary edits on a file. Now if we do that sgcompareandwrite again, it still fails but with a",
        "small difference:",
        "# sgcompareandwrite --in=ff00.bin --lba=0 --num=1 /dev/sg1",
        "Miscompare at byte offset: 3 [0x3]",
        "sgcompareandwrite failed: Miscompare",
        "So the bytes at offset 0, 1, and 2 compared equal but not the byte at offset 3. The SCSI COM‐",
        "PARE AND WRITE will stop on the first micompared byte."
    ],
    "see_also": [
        {
            "name": "sgreceivecopyresults",
            "section": "sg3utils",
            "url": "https://www.chedong.com/phpMan.php/man/sgreceivecopyresults/sg3utils/json"
        },
        {
            "name": "WRITE",
            "section": "8",
            "url": "https://www.chedong.com/phpMan.php/man/WRITE/8/json"
        }
    ]
}