The problem/use-case that the feature addresses
When using the "--scan" option, redis-cli uses a newline as the default separator between the keys it outputs. This is not ideal, since a key name may contain a newline character. This is especially problematic when piping the output of redis-cli to "xargs", where it would be natural to use the "-0" option to separate items.
Description of the feature
Add a new command line option ("--print0") to redis-cli. This option will have a similar affect to the "-print0" option of the "find" command, which causes it to separate its outputs using a null byte instead of a newline.
Naming the argument "print0" should make it recognizable to anyone familiar with the "find" command.
Alternatives you've considered
I could not think of an alternative as it is not possible to determine from the "scan" output whether two lines represent two keys or a single key that contains a newline character. The following output:
abc def
...could be two keys ("abc", "def") or it could be a single key "abc\ndef".
Additional information
As far as I can tell this should be a relatively straightforward addition to redis-cli.c. I have code ready to go if there is interest in this feature.
Comment From: zuiderkwast
This seems like a useful feature. Out of curiosity, I looked up which options are used for this by various commands.
GNU Coreutils:
-z, --zero-terminatedis used byhead,tail,sort,shuf,uniq,comm,cut,paste,joinandnumfmt. Some of these also accept-t '\0'.-z, --zerois used bymd5sum,readlink,basename,dirname,realpathandid.-0, --nullis used bydu,printenvandenv.
GNU Findutils:
--print0is used byfind.-0, --nullis used bylocateandxargs.
Comment From: jaypatrickhoward
Given most users will be using this option to pipe output to xargs, it may make more sense to copy the xargs syntax instead of what I originally proposed. I only chose the "find" syntax because that's where I see it used most often (to pipe to xargs).
Comment From: itamarhaber
I pity people who use newlines in their key names, this issue probably being the least of their problems ;) In the same spirit, I'd like to point that there may another set (subset? intersection of sorts?) of pitiful users who use other absurd characters in their key names (e.g. NULL), so having --print0 would still fail them.
The cli does have a way around this in non---scan mode, namely the --raw and --non-raw switches. Consider this:
$ redis-cli
127.0.0.1:6379> SET "new\x0Aline" foo
OK
127.0.0.1:6379> SET "null\xffteminator" bar
OK
127.0.0.1:6379> QUIT
$ redis-cli --raw keys "*"
null�teminator
new
line
$ redis-cli --no-raw keys "*"
1) "null\xffteminator"
2) "new\nline"
IMO, it would be better if --scan would also honor these. Would that address the problem with shell output pipelining?
Comment From: jaypatrickhoward
Would that address the problem with shell output pipelining?
Maybe! I'll experiment with raw/no-raw (using keys instead of scan) and see if it works. If so, I'll shift gears to having --scan honor them.
I actually didn't anticipate that it would be possible to use a null byte into a key name; figured they were required to be valid Unicode strings and not arbitrary sequences of bytes.
Comment From: itamarhaber
I actually didn't anticipate that it would be possible to use a null byte into a key name; figured they were required to be valid Unicode strings and not arbitrary sequences of bytes.
Redis' strings are "binary-safe", which basically means anything goes (or Garbage-In-Garbage-Out). The server can accept any byte array, including an empty one, as a valid string. Key names, string values and the nested values of most data types in Redis are like this.
Comment From: jaypatrickhoward
Using @yossigo's branch that enables --no-raw behavior for --scan, I'm still not able to delete keys with a newline by piping to xargs:
% ./redis-cli --scan
"new\nline"
% ./redis-cli --scan | xargs -n1 ./redis-cli del
(integer) 0
(integer) 0
A -0 option in conjunction with --scan --no-raw would do the trick (for both keys containing a null byte and those containing a newline) but maybe this is possible by fiddling around w/ xargs?
Comment From: yossigo
Because Redis is binary safe, any alternative-delimiter approach will have limited usability in some cases. But as redis-cli already has its own binary-safe notation, which just need to use it more.
It is already applied to input in TTY mode, i.e. this works:
redis-cli
127.0.0.1:6379> del "new\nline"
We need a flag to make that work also in non-TTY mode:
./redis-cli --scan --no-raw | xargs -n1 ./redis-cli --no-raw-input del
Comment From: yossigo
Fixed in #8566