CMPSB subtracts the byte at ES:DI from the byte at DS:SI, sets the flags from the result, throws the result away, and moves SI and DI to the next element (+1 with DF = 0, -1 with DF = 1; CMPSW compares words and steps by 2). Neither string changes.

Which way it subtracts

The flags are those of CMP DS:[SI], ES:[DI]: source minus destination. That is the opposite of what the register names suggest if you think of SUB dst, src. So after CMPSB, JB means the byte of the SI string was below the byte of the DI string. SCASB also subtracts the ES:DI element, from AL: in both, the ES:DI side is the right-hand operand of the comparison.

After CMPSJumps when
JE / JZ[SI] = [DI]
JB / JA[SI] below / above [DI], unsigned (text)
JL / JG[SI] less / greater than [DI], signed

Comparing strings

With REPE the comparison repeats while CX is not 0 and the elements are equal. When it stops, ZF tells you why: ZF = 1 means all CX elements matched, ZF = 0 means a difference. Test ZF, not CX: a difference in the very last element also leaves CX = 0. SI and DI then point one past the differing elements, so the 0-based index of the difference is SI - start - 1 (bytes, going forward). If CX was 0 to begin with, nothing is compared and the flags are left as they were.

CLD
MOV SI, OFFSET STR1
MOV DI, OFFSET STR2
MOV CX, 5
REPE CMPSB ; stop at the first difference
MOV DL, '=' ; MOV leaves the flags alone
JE SHOW1 ; all five equal
MOV DL, '<'
JB SHOW1 ; "e" is below "y"
MOV DL, '>'
SHOW1:
MOV AH, 02h
INT 21h
STR1 DB 'apple'
STR2 DB 'apply'

REPNE CMPSB is the opposite: it stops at the first position where the two strings are equal. A source override (CMPS BYTE PTR CS:[SI], ES:[DI]) is allowed; ES:DI is fixed. In an .EXE, set ES before comparing.