]>
git.saurik.com Git - redis.git/blob - src/redis-cli.c
42f74af84595a62da6b9cf35046c52b9e66ec243
   1 /* Redis CLI (command line interface) 
   3  * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com> 
   6  * Redistribution and use in source and binary forms, with or without 
   7  * modification, are permitted provided that the following conditions are met: 
   9  *   * Redistributions of source code must retain the above copyright notice, 
  10  *     this list of conditions and the following disclaimer. 
  11  *   * Redistributions in binary form must reproduce the above copyright 
  12  *     notice, this list of conditions and the following disclaimer in the 
  13  *     documentation and/or other materials provided with the distribution. 
  14  *   * Neither the name of Redis nor the names of its contributors may be used 
  15  *     to endorse or promote products derived from this software without 
  16  *     specific prior written permission. 
  18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  28  * POSSIBILITY OF SUCH DAMAGE. 
  47 #include "linenoise.h" 
  50 #define REDIS_NOTUSED(V) ((void) V) 
  52 static redisContext 
*context
; 
  53 static struct config 
{ 
  63     int stdinarg
; /* get last arg from stdin. (-x option) */ 
  65     int raw_output
; /* output mode per command */ 
  71 char *redisGitSHA1(void); 
  72 char *redisGitDirty(void); 
  74 /*------------------------------------------------------------------------------ 
  76  *--------------------------------------------------------------------------- */ 
  78 static long long mstime(void) { 
  82     gettimeofday(&tv
, NULL
); 
  83     mst 
= ((long)tv
.tv_sec
)*1000; 
  84     mst 
+= tv
.tv_usec
/1000; 
  88 static void cliRefreshPrompt(void) { 
  89     if (config
.dbnum 
== 0) 
  90         snprintf(config
.prompt
,sizeof(config
.prompt
),"redis %s:%d> ", 
  91             config
.hostip
, config
.hostport
); 
  93         snprintf(config
.prompt
,sizeof(config
.prompt
),"redis %s:%d[%d]> ", 
  94             config
.hostip
, config
.hostport
, config
.dbnum
); 
  97 /*------------------------------------------------------------------------------ 
  99  *--------------------------------------------------------------------------- */ 
 101 #define CLI_HELP_COMMAND 1 
 102 #define CLI_HELP_GROUP 2 
 110     /* Only used for help on commands */ 
 111     struct commandHelp 
*org
; 
 114 static helpEntry 
*helpEntries
; 
 115 static int helpEntriesLen
; 
 117 static sds 
cliVersion() { 
 119     version 
= sdscatprintf(sdsempty(), "%s", REDIS_VERSION
); 
 121     /* Add git commit and working tree status when available */ 
 122     if (strtoll(redisGitSHA1(),NULL
,16)) { 
 123         version 
= sdscatprintf(version
, " (git:%s", redisGitSHA1()); 
 124         if (strtoll(redisGitDirty(),NULL
,10)) 
 125             version 
= sdscatprintf(version
, "-dirty"); 
 126         version 
= sdscat(version
, ")"); 
 131 static void cliInitHelp() { 
 132     int commandslen 
= sizeof(commandHelp
)/sizeof(struct commandHelp
); 
 133     int groupslen 
= sizeof(commandGroups
)/sizeof(char*); 
 137     helpEntriesLen 
= len 
= commandslen
+groupslen
; 
 138     helpEntries 
= malloc(sizeof(helpEntry
)*len
); 
 140     for (i 
= 0; i 
< groupslen
; i
++) { 
 142         tmp
.argv 
= malloc(sizeof(sds
)); 
 143         tmp
.argv
[0] = sdscatprintf(sdsempty(),"@%s",commandGroups
[i
]); 
 144         tmp
.full 
= tmp
.argv
[0]; 
 145         tmp
.type 
= CLI_HELP_GROUP
; 
 147         helpEntries
[pos
++] = tmp
; 
 150     for (i 
= 0; i 
< commandslen
; i
++) { 
 151         tmp
.argv 
= sdssplitargs(commandHelp
[i
].name
,&tmp
.argc
); 
 152         tmp
.full 
= sdsnew(commandHelp
[i
].name
); 
 153         tmp
.type 
= CLI_HELP_COMMAND
; 
 154         tmp
.org 
= &commandHelp
[i
]; 
 155         helpEntries
[pos
++] = tmp
; 
 159 /* Output command help to stdout. */ 
 160 static void cliOutputCommandHelp(struct commandHelp 
*help
, int group
) { 
 161     printf("\r\n  \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help
->name
, help
->params
); 
 162     printf("  \x1b[33msummary:\x1b[0m %s\r\n", help
->summary
); 
 163     printf("  \x1b[33msince:\x1b[0m %s\r\n", help
->since
); 
 165         printf("  \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups
[help
->group
]); 
 169 /* Print generic help. */ 
 170 static void cliOutputGenericHelp() { 
 171     sds version 
= cliVersion(); 
 174         "Type: \"help @<group>\" to get a list of commands in <group>\r\n" 
 175         "      \"help <command>\" for help on <command>\r\n" 
 176         "      \"help <tab>\" to get a list of possible help topics\r\n" 
 177         "      \"quit\" to exit\r\n", 
 183 /* Output all command help, filtering by group or command name. */ 
 184 static void cliOutputHelp(int argc
, char **argv
) { 
 188     struct commandHelp 
*help
; 
 191         cliOutputGenericHelp(); 
 193     } else if (argc 
> 0 && argv
[0][0] == '@') { 
 194         len 
= sizeof(commandGroups
)/sizeof(char*); 
 195         for (i 
= 0; i 
< len
; i
++) { 
 196             if (strcasecmp(argv
[0]+1,commandGroups
[i
]) == 0) { 
 204     for (i 
= 0; i 
< helpEntriesLen
; i
++) { 
 205         entry 
= &helpEntries
[i
]; 
 206         if (entry
->type 
!= CLI_HELP_COMMAND
) continue; 
 210             /* Compare all arguments */ 
 211             if (argc 
== entry
->argc
) { 
 212                 for (j 
= 0; j 
< argc
; j
++) { 
 213                     if (strcasecmp(argv
[j
],entry
->argv
[j
]) != 0) break; 
 216                     cliOutputCommandHelp(help
,1); 
 220             if (group 
== help
->group
) { 
 221                 cliOutputCommandHelp(help
,0); 
 228 static void completionCallback(const char *buf
, linenoiseCompletions 
*lc
) { 
 235     if (strncasecmp(buf
,"help ",5) == 0) { 
 237         while (isspace(buf
[startpos
])) startpos
++; 
 238         mask 
= CLI_HELP_COMMAND 
| CLI_HELP_GROUP
; 
 240         mask 
= CLI_HELP_COMMAND
; 
 243     for (i 
= 0; i 
< helpEntriesLen
; i
++) { 
 244         if (!(helpEntries
[i
].type 
& mask
)) continue; 
 246         matchlen 
= strlen(buf
+startpos
); 
 247         if (strncasecmp(buf
+startpos
,helpEntries
[i
].full
,matchlen
) == 0) { 
 248             tmp 
= sdsnewlen(buf
,startpos
); 
 249             tmp 
= sdscat(tmp
,helpEntries
[i
].full
); 
 250             linenoiseAddCompletion(lc
,tmp
); 
 256 /*------------------------------------------------------------------------------ 
 257  * Networking / parsing 
 258  *--------------------------------------------------------------------------- */ 
 260 /* Send AUTH command to the server */ 
 261 static int cliAuth() { 
 263     if (config
.auth 
== NULL
) return REDIS_OK
; 
 265     reply 
= redisCommand(context
,"AUTH %s",config
.auth
); 
 267         freeReplyObject(reply
); 
 273 /* Send SELECT dbnum to the server */ 
 274 static int cliSelect() { 
 276     if (config
.dbnum 
== 0) return REDIS_OK
; 
 278     reply 
= redisCommand(context
,"SELECT %d",config
.dbnum
); 
 280         freeReplyObject(reply
); 
 286 /* Connect to the client. If force is not zero the connection is performed 
 287  * even if there is already a connected socket. */ 
 288 static int cliConnect(int force
) { 
 289     if (context 
== NULL 
|| force
) { 
 293         if (config
.hostsocket 
== NULL
) { 
 294             context 
= redisConnect(config
.hostip
,config
.hostport
); 
 296             context 
= redisConnectUnix(config
.hostsocket
); 
 300             fprintf(stderr
,"Could not connect to Redis at "); 
 301             if (config
.hostsocket 
== NULL
) 
 302                 fprintf(stderr
,"%s:%d: %s\n",config
.hostip
,config
.hostport
,context
->errstr
); 
 304                 fprintf(stderr
,"%s: %s\n",config
.hostsocket
,context
->errstr
); 
 310         /* Do AUTH and select the right DB. */ 
 311         if (cliAuth() != REDIS_OK
) 
 313         if (cliSelect() != REDIS_OK
) 
 319 static void cliPrintContextError() { 
 320     if (context 
== NULL
) return; 
 321     fprintf(stderr
,"Error: %s\n",context
->errstr
); 
 324 static sds 
cliFormatReplyTTY(redisReply 
*r
, char *prefix
) { 
 325     sds out 
= sdsempty(); 
 327     case REDIS_REPLY_ERROR
: 
 328         out 
= sdscatprintf(out
,"(error) %s\n", r
->str
); 
 330     case REDIS_REPLY_STATUS
: 
 331         out 
= sdscat(out
,r
->str
); 
 332         out 
= sdscat(out
,"\n"); 
 334     case REDIS_REPLY_INTEGER
: 
 335         out 
= sdscatprintf(out
,"(integer) %lld\n",r
->integer
); 
 337     case REDIS_REPLY_STRING
: 
 338         /* If you are producing output for the standard output we want 
 339         * a more interesting output with quoted characters and so forth */ 
 340         out 
= sdscatrepr(out
,r
->str
,r
->len
); 
 341         out 
= sdscat(out
,"\n"); 
 343     case REDIS_REPLY_NIL
: 
 344         out 
= sdscat(out
,"(nil)\n"); 
 346     case REDIS_REPLY_ARRAY
: 
 347         if (r
->elements 
== 0) { 
 348             out 
= sdscat(out
,"(empty list or set)\n"); 
 350             unsigned int i
, idxlen 
= 0; 
 356             /* Calculate chars needed to represent the largest index */ 
 363             /* Prefix for nested multi bulks should grow with idxlen+2 spaces */ 
 364             memset(_prefixlen
,' ',idxlen
+2); 
 365             _prefixlen
[idxlen
+2] = '\0'; 
 366             _prefix 
= sdscat(sdsnew(prefix
),_prefixlen
); 
 368             /* Setup prefix format for every entry */ 
 369             snprintf(_prefixfmt
,sizeof(_prefixfmt
),"%%s%%%dd) ",idxlen
); 
 371             for (i 
= 0; i 
< r
->elements
; i
++) { 
 372                 /* Don't use the prefix for the first element, as the parent 
 373                  * caller already prepended the index number. */ 
 374                 out 
= sdscatprintf(out
,_prefixfmt
,i 
== 0 ? "" : prefix
,i
+1); 
 376                 /* Format the multi bulk entry */ 
 377                 tmp 
= cliFormatReplyTTY(r
->element
[i
],_prefix
); 
 378                 out 
= sdscatlen(out
,tmp
,sdslen(tmp
)); 
 385         fprintf(stderr
,"Unknown reply type: %d\n", r
->type
); 
 391 static sds 
cliFormatReplyRaw(redisReply 
*r
) { 
 392     sds out 
= sdsempty(), tmp
; 
 396     case REDIS_REPLY_NIL
: 
 399     case REDIS_REPLY_ERROR
: 
 400         out 
= sdscatlen(out
,r
->str
,r
->len
); 
 401         out 
= sdscatlen(out
,"\n",1); 
 403     case REDIS_REPLY_STATUS
: 
 404     case REDIS_REPLY_STRING
: 
 405         out 
= sdscatlen(out
,r
->str
,r
->len
); 
 407     case REDIS_REPLY_INTEGER
: 
 408         out 
= sdscatprintf(out
,"%lld",r
->integer
); 
 410     case REDIS_REPLY_ARRAY
: 
 411         for (i 
= 0; i 
< r
->elements
; i
++) { 
 412             if (i 
> 0) out 
= sdscat(out
,config
.mb_delim
); 
 413             tmp 
= cliFormatReplyRaw(r
->element
[i
]); 
 414             out 
= sdscatlen(out
,tmp
,sdslen(tmp
)); 
 419         fprintf(stderr
,"Unknown reply type: %d\n", r
->type
); 
 425 static int cliReadReply(int output_raw_strings
) { 
 430     if (redisGetReply(context
,&_reply
) != REDIS_OK
) { 
 433         if (config
.interactive
) { 
 434             /* Filter cases where we should reconnect */ 
 435             if (context
->err 
== REDIS_ERR_IO 
&& errno 
== ECONNRESET
) 
 437             if (context
->err 
== REDIS_ERR_EOF
) 
 440         cliPrintContextError(); 
 442         return REDIS_ERR
; /* avoid compiler warning */ 
 445     reply 
= (redisReply
*)_reply
; 
 446     if (output_raw_strings
) { 
 447         out 
= cliFormatReplyRaw(reply
); 
 449         if (config
.raw_output
) { 
 450             out 
= cliFormatReplyRaw(reply
); 
 451             out 
= sdscat(out
,"\n"); 
 453             out 
= cliFormatReplyTTY(reply
,""); 
 456     fwrite(out
,sdslen(out
),1,stdout
); 
 458     freeReplyObject(reply
); 
 462 static int cliSendCommand(int argc
, char **argv
, int repeat
) { 
 463     char *command 
= argv
[0]; 
 467     if (context 
== NULL
) return REDIS_ERR
; 
 470     if (!strcasecmp(command
,"info") || 
 471         (argc 
== 2 && !strcasecmp(command
,"cluster") && 
 472                       (!strcasecmp(argv
[1],"nodes") || 
 473                        !strcasecmp(argv
[1],"info"))) || 
 474         (argc 
== 2 && !strcasecmp(command
,"client") && 
 475                        !strcasecmp(argv
[1],"list"))) 
 481     if (!strcasecmp(command
,"help") || !strcasecmp(command
,"?")) { 
 482         cliOutputHelp(--argc
, ++argv
); 
 485     if (!strcasecmp(command
,"shutdown")) config
.shutdown 
= 1; 
 486     if (!strcasecmp(command
,"monitor")) config
.monitor_mode 
= 1; 
 487     if (!strcasecmp(command
,"subscribe") || 
 488         !strcasecmp(command
,"psubscribe")) config
.pubsub_mode 
= 1; 
 490     /* Setup argument length */ 
 491     argvlen 
= malloc(argc
*sizeof(size_t)); 
 492     for (j 
= 0; j 
< argc
; j
++) 
 493         argvlen
[j
] = sdslen(argv
[j
]); 
 496         redisAppendCommandArgv(context
,argc
,(const char**)argv
,argvlen
); 
 497         while (config
.monitor_mode
) { 
 498             if (cliReadReply(output_raw
) != REDIS_OK
) exit(1); 
 502         if (config
.pubsub_mode
) { 
 503             if (!config
.raw_output
) 
 504                 printf("Reading messages... (press Ctrl-C to quit)\n"); 
 506                 if (cliReadReply(output_raw
) != REDIS_OK
) exit(1); 
 510         if (cliReadReply(output_raw
) != REDIS_OK
) { 
 514             /* Store database number when SELECT was successfully executed. */ 
 515             if (!strcasecmp(command
,"select") && argc 
== 2) { 
 516                 config
.dbnum 
= atoi(argv
[1]); 
 526 /*------------------------------------------------------------------------------ 
 528  *--------------------------------------------------------------------------- */ 
 530 static int parseOptions(int argc
, char **argv
) { 
 533     for (i 
= 1; i 
< argc
; i
++) { 
 534         int lastarg 
= i
==argc
-1; 
 536         if (!strcmp(argv
[i
],"-h") && !lastarg
) { 
 537             sdsfree(config
.hostip
); 
 538             config
.hostip 
= sdsnew(argv
[i
+1]); 
 540         } else if (!strcmp(argv
[i
],"-h") && lastarg
) { 
 542         } else if (!strcmp(argv
[i
],"--help")) { 
 544         } else if (!strcmp(argv
[i
],"-x")) { 
 546         } else if (!strcmp(argv
[i
],"-p") && !lastarg
) { 
 547             config
.hostport 
= atoi(argv
[i
+1]); 
 549         } else if (!strcmp(argv
[i
],"-s") && !lastarg
) { 
 550             config
.hostsocket 
= argv
[i
+1]; 
 552         } else if (!strcmp(argv
[i
],"-r") && !lastarg
) { 
 553             config
.repeat 
= strtoll(argv
[i
+1],NULL
,10); 
 555         } else if (!strcmp(argv
[i
],"-n") && !lastarg
) { 
 556             config
.dbnum 
= atoi(argv
[i
+1]); 
 558         } else if (!strcmp(argv
[i
],"-a") && !lastarg
) { 
 559             config
.auth 
= argv
[i
+1]; 
 561         } else if (!strcmp(argv
[i
],"--raw")) { 
 562             config
.raw_output 
= 1; 
 563         } else if (!strcmp(argv
[i
],"-d") && !lastarg
) { 
 564             sdsfree(config
.mb_delim
); 
 565             config
.mb_delim 
= sdsnew(argv
[i
+1]); 
 567         } else if (!strcmp(argv
[i
],"-v") || !strcmp(argv
[i
], "--version")) { 
 568             sds version 
= cliVersion(); 
 569             printf("redis-cli %s\n", version
); 
 579 static sds 
readArgFromStdin(void) { 
 581     sds arg 
= sdsempty(); 
 584         int nread 
= read(fileno(stdin
),buf
,1024); 
 586         if (nread 
== 0) break; 
 587         else if (nread 
== -1) { 
 588             perror("Reading from standard input"); 
 591         arg 
= sdscatlen(arg
,buf
,nread
); 
 596 static void usage() { 
 597     sds version 
= cliVersion(); 
 601 "Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n" 
 602 "  -h <hostname>    Server hostname (default: 127.0.0.1)\n" 
 603 "  -p <port>        Server port (default: 6379)\n" 
 604 "  -s <socket>      Server socket (overrides hostname and port)\n" 
 605 "  -a <password>    Password to use when connecting to the server\n" 
 606 "  -r <repeat>      Execute specified command N times\n" 
 607 "  -n <db>          Database number\n" 
 608 "  -x               Read last argument from STDIN\n" 
 609 "  -d <delimiter>   Multi-bulk delimiter in for raw formatting (default: \\n)\n" 
 610 "  --raw            Use raw formatting for replies (default when STDOUT is not a tty)\n" 
 611 "  --help           Output this help and exit\n" 
 612 "  --version        Output version and exit\n" 
 615 "  cat /etc/passwd | redis-cli -x set mypasswd\n" 
 616 "  redis-cli get mypasswd\n" 
 617 "  redis-cli -r 100 lpush mylist x\n" 
 619 "When no command is given, redis-cli starts in interactive mode.\n" 
 620 "Type \"help\" in interactive mode for information on available commands.\n" 
 627 /* Turn the plain C strings into Sds strings */ 
 628 static char **convertToSds(int count
, char** args
) { 
 630   char **sds 
= zmalloc(sizeof(char*)*count
); 
 632   for(j 
= 0; j 
< count
; j
++) 
 633     sds
[j
] = sdsnew(args
[j
]); 
 638 #define LINE_BUFLEN 4096 
 640     sds historyfile 
= NULL
; 
 646     config
.interactive 
= 1; 
 647     linenoiseSetCompletionCallback(completionCallback
); 
 649     /* Only use history when stdin is a tty. */ 
 650     if (isatty(fileno(stdin
))) { 
 653         if (getenv("HOME") != NULL
) { 
 654             historyfile 
= sdscatprintf(sdsempty(),"%s/.rediscli_history",getenv("HOME")); 
 655             linenoiseHistoryLoad(historyfile
); 
 660     while((line 
= linenoise(context 
? config
.prompt 
: "not connected> ")) != NULL
) { 
 661         if (line
[0] != '\0') { 
 662             argv 
= sdssplitargs(line
,&argc
); 
 663             if (history
) linenoiseHistoryAdd(line
); 
 664             if (historyfile
) linenoiseHistorySave(historyfile
); 
 667                 printf("Invalid argument(s)\n"); 
 669             } else if (argc 
> 0) { 
 670                 if (strcasecmp(argv
[0],"quit") == 0 || 
 671                     strcasecmp(argv
[0],"exit") == 0) 
 674                 } else if (argc 
== 3 && !strcasecmp(argv
[0],"connect")) { 
 675                     sdsfree(config
.hostip
); 
 676                     config
.hostip 
= sdsnew(argv
[1]); 
 677                     config
.hostport 
= atoi(argv
[2]); 
 679                 } else if (argc 
== 1 && !strcasecmp(argv
[0],"clear")) { 
 680                     linenoiseClearScreen(); 
 682                     long long start_time 
= mstime(), elapsed
; 
 683                     int repeat
, skipargs 
= 0; 
 685                     repeat 
= atoi(argv
[0]); 
 692                     if (cliSendCommand(argc
-skipargs
,argv
+skipargs
,repeat
) 
 697                         /* If we still cannot send the command print error. 
 698                          * We'll try to reconnect the next time. */ 
 699                         if (cliSendCommand(argc
-skipargs
,argv
+skipargs
,repeat
) 
 701                             cliPrintContextError(); 
 703                     elapsed 
= mstime()-start_time
; 
 704                     if (elapsed 
>= 500) { 
 705                         printf("(%.2fs)\n",(double)elapsed
/1000); 
 709             /* Free the argument vector */ 
 710             while(argc
--) sdsfree(argv
[argc
]); 
 713         /* linenoise() returns malloc-ed lines like readline() */ 
 719 static int noninteractive(int argc
, char **argv
) { 
 721     if (config
.stdinarg
) { 
 722         argv 
= zrealloc(argv
, (argc
+1)*sizeof(char*)); 
 723         argv
[argc
] = readArgFromStdin(); 
 724         retval 
= cliSendCommand(argc
+1, argv
, config
.repeat
); 
 726         /* stdin is probably a tty, can be tested with S_ISCHR(s.st_mode) */ 
 727         retval 
= cliSendCommand(argc
, argv
, config
.repeat
); 
 732 int main(int argc
, char **argv
) { 
 735     config
.hostip 
= sdsnew("127.0.0.1"); 
 736     config
.hostport 
= 6379; 
 737     config
.hostsocket 
= NULL
; 
 740     config
.interactive 
= 0; 
 742     config
.monitor_mode 
= 0; 
 743     config
.pubsub_mode 
= 0; 
 746     config
.raw_output 
= !isatty(fileno(stdout
)) && (getenv("FAKETTY") == NULL
); 
 747     config
.mb_delim 
= sdsnew("\n"); 
 750     firstarg 
= parseOptions(argc
,argv
); 
 754     /* Start interactive mode when no command is provided */ 
 756         /* Note that in repl mode we don't abort on connection error. 
 757          * A new attempt will be performed for every command send. */ 
 762     /* Otherwise, we have some arguments to execute */ 
 763     if (cliConnect(0) != REDIS_OK
) exit(1); 
 764     return noninteractive(argc
,convertToSds(argc
,argv
));