如何得到所有的键与他们的值在重排

我知道为了得到 Redis 所有键的列表,我必须使用 KEYS *,但是有没有办法把所有键和它们的值一起输出呢?

几分钟的搜索没有得到任何结果。

另外,非常感谢你的回答,但我正在寻找一个本土的解决方案。我可以自己编写一个函数来遍历 KEYS *的所有输出。

186742 次浏览

KEYS command should not be used on Redis production instances if you have a lot of keys, since it may block the Redis event loop for several seconds.

I would generate a dump (bgsave), and then use the following Python package to parse it and extract the data:

https://github.com/sripathikrishnan/redis-rdb-tools

You can have json output, or customize your own output in Python.

check out my tool, rdd

rdd -v

will output you all keys with data

I have written a small code for this particular requirement using hiredis , please find the code with a working example at http://rachitjain1.blogspot.in/2013/10/how-to-get-all-keyvalue-in-redis-db.html

Here is the code that I have written,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hiredis.h"


int main(void)
{
unsigned int i,j=0;char **str1;
redisContext *c; char *t;
redisReply *reply, *rep;


struct timeval timeout = { 1, 500000 }; // 1.5 seconds
c = redisConnectWithTimeout((char*)"127.0.0.2", 6903, timeout);
if (c->err) {
printf("Connection error: %s\n", c->errstr);
exit(1);
}


reply = redisCommand(c,"keys *");
printf("KEY\t\tVALUE\n");
printf("------------------------\n");
while ( reply->element[j]->str != NULL)
{
rep = redisCommand(c,"GET  %s", reply->element[j]->str);
if (strstr(rep->str,"ERR Operation against a key holding"))
{
printf("%s\t\t%s\n",  reply->element[j]->str,rep->str);
break;
}
printf("%s\t\t%s\n",  reply->element[j]->str,rep->str);
j++;
freeReplyObject(rep);
}
}

There is no native way of doing this.

The Redis command documentation contains no native commands for getting the key and value of multiple keys.

The most native way of doing this would be to load a lua script into your redis using the SCRIPT LOAD command or the EVAL command.

Bash Haxx solution

A workaround would be to use some bash magic, like this:

echo 'keys YOURKEY*' | redis-cli | sed 's/^/get /' | redis-cli

This will output the data from all the keys which begin with YOURKEY

Note that the keys command is a blocking operation and should be used with care.

Yes, you can do print all keys using below bash script,

for key in $(redis-cli -p 6379 keys \*);
do echo "Key : '$key'"
redis-cli -p 6379 GET $key;
done

where, 6379 is a port on which redis is running.

I had the same problem, and I felt on your post.

I think the easiest way to solve this issue is by using redis Hashtable.

It allows you to save a Hash, with different fields and values associated with every field.

To get all the fiels and values client.HGETALLL does the trick. It returns an array of

all the fields followed by their values.

More informations here https://redis.io/commands/hgetall

scan 0 MATCH * COUNT 1000 // it gets all the keys if return is "0" as first element then count is less than 1000 if more then it will return the pointer as first element and >scan pointer_val MATCH * COUNT 1000 to get the next set of keys it continues till the first value is "0".

I refined the bash solution a bit, so that the more efficient scan is used instead of keys, and printing out array and hash values is supported. My solution also prints out the key name.

redis_print.sh:

#!/bin/bash


# Default to '*' key pattern, meaning all redis keys in the namespace
REDIS_KEY_PATTERN="${REDIS_KEY_PATTERN:-*}"
for key in $(redis-cli --scan --pattern "$REDIS_KEY_PATTERN")
do
type=$(redis-cli type $key)
if [ $type = "list" ]
then
printf "$key => \n$(redis-cli lrange $key 0 -1 | sed 's/^/  /')\n"
elif [ $type = "hash" ]
then
printf "$key => \n$(redis-cli hgetall $key | sed 's/^/  /')\n"
else
printf "$key => $(redis-cli get $key)\n"
fi
done

Note: you can formulate a one-liner of this script by removing the first line of redis_print.sh and commanding: cat redis_print.sh | tr '\n' ';' | awk '$1=$1'

You can use MGET to get the values of multiple keys in a single go.

Example:

redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> MGET key1 key2 nonexisting
1) "Hello"
2) "World"
3) (nil)

For listing out all keys & values you'll probably have to use bash or something similar, but MGET can help in listing all the values when you know which keys to look for beforehand.

Use this script for redis >=5:

#!/bin/bash
redis-cli keys "*" > keys.txt
cat keys.txt | awk '{ printf "type %s\n", $1 }' | redis-cli > types.txt
paste -d'|' keys.txt types.txt | awk -F\| '
$2 == "string"               { printf "echo \"KEY %s %s\"\nget %s\n", $1, $2, $1 }
$2 == "list" || $2 == "set"  { printf "echo \"KEY %s %s\"\nsort %s by nosort\n", $1, $2, $1 }
$2 == "hash"                 { printf "echo \"KEY %s %s\"\nhgetall %s\n", $1, $2, $1 }
$2 == "zset"                 { printf "echo \"KEY %s %s\"\nzrange %s 0 -1 withscores\n", $1, $2,$1 }
' | redis-cli
rm keys.txt
rm types.txt

Tried the given example, but over VPN and with 400k+ keys it was too slow for me. Also it did not give me the key objects.

I wrote a small Python called tool redis-mass-get to combine KEYS and MGET requests against Redis:

# installation:
pip install redis-mass-get


# pipeline example CSV:
redis-mass-get -f csv -och redis://my.redis.url product:* | less


# write to json-file example with progress indicator:
redis-mass-get -d results.json -jd redis://my.redis.url product:*

It supports JSON, CSV and TXT output to file or stdout for usage in pipes. More info can be found at: Reading multiple key/values from Redis.

Below is just a little variant of the script provided by @"Juuso Ohtonen".

I have add a password variable and counter so you can can check the progression of your backup. Also I replaced simple brackets [] by double brackets [[]] to prevent an error I had on macos.

1. Get the total number of keys

$ sudo redis-cli
INFO keyspace
AUTH yourpassword
INFO keyspace

2. Edit the script

#!/bin/bash


# Default to '*' key pattern, meaning all redis keys in the namespace
REDIS_KEY_PATTERN="${REDIS_KEY_PATTERN:-*}"
PASS="yourpassword"
i=1
for key in $(redis-cli -a "$PASS" --scan --pattern "$REDIS_KEY_PATTERN")
do
echo $i.
((i=i+1))
type=$(redis-cli -a "$PASS" type $key)
if [[ $type = "list" ]]
then
printf "$key => \n$(redis-cli -a "$PASS" lrange $key 0 -1 | sed 's/^/  /')\n"
elif [[ $type = "hash" ]]
then
printf "$key => \n$(redis-cli -a "$PASS" hgetall $key | sed 's/^/  /')\n"
else
printf "$key => $(redis-cli -a "$PASS" get $key)\n"
fi
echo
done

3. Execute the script

bash redis_print.sh > redis.bak

4. Check progression

tail redis.bak

This simple script worked for me (I store in my REDIS key-value sets)

#!/bin/bash


for key in $(redis-cli -p <port> -n <db num> keys \*);
do
OUTPUT=$(redis-cli -p <port> -n <db num> GET $key)
echo "$key", "${OUTPUT}" >> redis_pairs.csv
done

You simply execute it:

$ chmod +x script.sh
$ ./script.sh

The final output is a .csv file (comma delimiter) of the pairs I needed.

I have updated the script with some more keys and here goes

#!/bin/bash


# Default to '*' key pattern, meaning all redis keys in the namespace
REDIS_KEY_PATTERN="${REDIS_KEY_PATTERN:-*}"
for key in $(redis-cli --scan --pattern "$REDIS_KEY_PATTERN")
do
type=$(redis-cli type $key)
if [ $type = "list" ]
then
printf "$key => \n$(redis-cli lrange $key 0 -1 | sed 's/^/  /')\n"
elif [ $type = "hash" ]
then
printf "$key => \n$(redis-cli hgetall $key | sed 's/^/  /')\n"
elif [ $type = "smembers" ]
then
printf "$key => $(redis-cli smembers $key)\n"
elif [ $type = "zset" ]
then
printf "$key => $(redis-cli zrange $key 0 -1)\n"
elif [ $type = "set" ]
then
printf "$key => $(redis-cli smembers $key)\n"
else
printf "$key => $(redis-cli get $key)\n"


fi
done

Check out solution for Alpine linux container

  • Create file redis

    #!/bin/bash
    apk --update add redis
    host="$1"
    port="$2"
    
    
    redis-cli -h "${host}" -p "${port}" --scan --pattern 'key_prefix_*' | while read key;
    do
    value=$(redis-cli -h "${host}" -p "${port}" get "${key}")
    echo "${key} : ${value}"
    done
    
  • Run: chmod 755 redis

  • Run: /bin/sh redis {Your Redis Host} {Your Redis Port}