Repository: redis/redis

Issue:
[BUG] Wrong response in redis-cli after unsubscribing channels and use another command to get data.
**Describe the bug**
I was using `redis-cli` to communicate with `redis-server`.
First I used `UNSUBSCRIBE` command to unsubscribe multiple channels (I did not use `SUBSCRIBE` command to subscribe those channels). And then I tried to use `SET` or other commands (may be `LRANGE`) to get some data from the `redis-server`, but I got the unexpected response.

**To reproduce**
`Environment:` 
* redis-server: Redis server v=7.0.3 sha=00000000:0 malloc=jemalloc-5.2.1 bits=64 build=9e1e27bf47eab674
* redis-cli: redis-cli 7.0.3
* OS: Ubuntu 16.04

Steps to reproduce the behavior and/or a minimal code sample.
![image](https://user-images.githubusercontent.com/28601090/181213225-a0487fd1-cade-4889-bd62-db6c87e79c46.png)

**Expected behavior**
I think the `GET a` command should return `100` right after I use `UNSUBSCRIBE ch1 ch2`, rather than the response from `UNSUBSCRIBE` command.


Discussion:
thanks for reporting, indeed a bug (redis-cli bug), i tested in unstable branch
it seems like the protocol is broken by the UNSUBSCRIBE command (returning multiple RESP replies).
and it seems to have existed in previous versions as well.
> it seems like the protocol is broken by the UNSUBSCRIBE command (returning multiple RESP replies).
and it seems to have existed in previous versions as well.

yes and yes, i suppose we need to read the specified number of replies according to the number of parameters.
i am testing it. have a demo fix, didn't test in cluster mode..

It's just that the code's special handling of SUBSCRIBE related commands... i will make a PR and see how it will work

Patch:
diff --git a/src/redis-cli.c b/src/redis-cli.c
index 5f3bc78d4de..eb24d559954 100644
--- a/src/redis-cli.c
+++ b/src/redis-cli.c
@@ -1728,6 +1728,7 @@ static int cliSendCommand(int argc, char **argv, long repeat) {
     char *command = argv[0];
     size_t *argvlen;
     int j, output_raw;
+    int is_unsubscribe_command = 0; /* Is it an unsubscribe related command? */
 
     if (context == NULL) return REDIS_ERR;
 
@@ -1766,6 +1767,9 @@ static int cliSendCommand(int argc, char **argv, long repeat) {
     if (!strcasecmp(command,"subscribe") ||
         !strcasecmp(command,"psubscribe") ||
         !strcasecmp(command,"ssubscribe")) config.pubsub_mode = 1;
+    if (!strcasecmp(command,"unsubscribe") ||
+        !strcasecmp(command,"punsubscribe") ||
+        !strcasecmp(command,"sunsubscribe")) is_unsubscribe_command = 1;
     if (!strcasecmp(command,"sync") ||
         !strcasecmp(command,"psync")) config.slave_mode = 1;
 
@@ -1796,6 +1800,22 @@ static int cliSendCommand(int argc, char **argv, long repeat) {
        works well with the interval option. */
     while(repeat < 0 || repeat-- > 0) {
         redisAppendCommandArgv(context,argc,(const char**)argv,argvlen);
+
+        if (is_unsubscribe_command) {
+            /* In unsubscribe related commands, we need to read the specified
+             * number of replies according to the number of parameters. */
+            argc--; /* Skip the command */
+            do {
+                if (cliReadReply(output_raw) != REDIS_OK) {
+                    cliPrintContextError();
+                    exit(1);
+                }
+                fflush(stdout);
+            } while(--argc);
+            zfree(argvlen);
+            continue;
+        }
+
         if (config.monitor_mode) {
             do {
                 if (cliReadReply(output_raw) != REDIS_OK) {