Hi, This patch for bash 3.1 adds a "-i" option to the read builtin. When this option is present and readline is being used (ie. -e also specified), it specifies the "initial text", which is placed into the readline edit buffer. This allows a "default" value to be automatically included on the user's edit line - if the user just presses Enter, then that value will be put into $REPLY, otherwise the user can edit the value before pressing Enter.
An example of the usefulness of this is when renaming files. I find that frequently when I am renaming files, the new name closely resembles the old name. Eg. adding ".old" to the end, adding "new_" to the front, etc. I have the following function in my .bash_profile: function rnm { local newname if [ $# = 1 ]; then read -e -p "New filename: " -i "$1" newname mv -i "$1" "$newname" else mv -i "$@" fi } export -f rnm This lets me rename files very easily: bash-3.1$ rnm somefile.txt New filename: somefile.txt Now I can type ".old<Enter>", or "^Anew_<Enter>", or perhaps even "^A<RightArrow*4>other<Enter>", and so on. Without the -i option to read, I have to spell out both the old and new filenames in the mv command. Even with tab completion, if the filenames are long and in a directory with many similarly-named files, this can be tedious. I'm sure that there are potentially other uses for this option. The patch is fairly straightforward and unintrusive. I'd appreciate any feedback on it. Thanks. Kev. --- bash-3.1/builtins/read.def 2005-08-21 11:46:19.000000000 +1000 +++ bash-3.1kp1/builtins/read.def 2006-07-18 14:00:00.000000000 +1000 @@ -23,7 +23,7 @@ $BUILTIN read $FUNCTION read_builtin -$SHORT_DOC read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...] +$SHORT_DOC read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [-i initial] [name ...] One line is read from the standard input, or from file descriptor FD if the -u option is supplied, and the first word is assigned to the first NAME, the second word to the second NAME, and so on, with leftover words assigned @@ -38,7 +38,9 @@ the shell is interactive, readline is used to obtain the line. If -n is supplied with a non-zero NCHARS argument, read returns after NCHARS characters have been read. The -s option causes input coming from a -terminal to not be echoed. +terminal to not be echoed. If the -i option is given and readline is being +used, the string following it is the `default' or `initial' string that is +placed into the edit buffer prior to obtaining the user's input. The -t option causes read to time out and return failure if a complete line of input is not read within TIMEOUT seconds. If the TMOUT variable is set, @@ -90,7 +92,7 @@ extern int interrupt_immediately; #if defined (READLINE) -static char *edit_line __P((char *)); +static char *edit_line __P((char *, char *)); static void set_eol_delim __P((int)); static void reset_eol_delim __P((char *)); #endif @@ -134,7 +136,7 @@ unsigned int tmout; intmax_t intval; char c; - char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname; + char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname, *initial; char *e, *t, *t1; struct stat tsb; SHELL_VAR *var; @@ -159,6 +161,7 @@ USE_VAR(ifs_chars); USE_VAR(prompt); USE_VAR(arrayname); + USE_VAR(initial); #if defined (READLINE) USE_VAR(rlbuf); USE_VAR(rlind); @@ -168,7 +171,7 @@ i = 0; /* Index into the string that we are reading. */ raw = edit = 0; /* Not reading raw input by default. */ silent = 0; - arrayname = prompt = (char *)NULL; + arrayname = prompt = initial = (char *)NULL; fd = 0; /* file descriptor to read from */ #if defined (READLINE) @@ -181,7 +184,7 @@ delim = '\n'; /* read until newline */ reset_internal_getopt (); - while ((opt = internal_getopt (list, "ersa:d:n:p:t:u:")) != -1) + while ((opt = internal_getopt (list, "ersa:d:n:p:i:t:u:")) != -1) { switch (opt) { @@ -191,6 +194,9 @@ case 'p': prompt = list_optarg; break; + case 'i': + initial = list_optarg; + break; case 's': silent = 1; break; @@ -294,7 +300,7 @@ terminal, turn them off. */ if ((prompt || edit || silent) && input_is_tty == 0) { - prompt = (char *)NULL; + prompt = initial = (char *)NULL; edit = silent = 0; } @@ -394,7 +400,7 @@ } if (rlbuf == 0) { - rlbuf = edit_line (prompt ? prompt : ""); + rlbuf = edit_line (prompt ? prompt : "", initial); rlind = 0; } if (rlbuf == 0) @@ -689,10 +695,31 @@ #if defined (READLINE) static rl_completion_func_t *old_attempted_completion_function; +static rl_hook_func_t *old_startup_hook; +static char *initial_text; + +int +set_initial_text (void) +{ + int rc1, rc2; + + rc1 = rc2 = 0; + if (old_startup_hook) + rc1 = (*old_startup_hook)(); + if (initial_text) + { + rc2 = rl_insert_text(initial_text); + initial_text = (char *)NULL; + rl_startup_hook = old_startup_hook; + old_startup_hook = (rl_hook_func_t *)NULL; + } + return rc1 || rc2; +} static char * -edit_line (p) +edit_line (p, i) char *p; + char *i; { char *ret; int len; @@ -701,6 +728,12 @@ initialize_readline (); old_attempted_completion_function = rl_attempted_completion_function; rl_attempted_completion_function = (rl_completion_func_t *)NULL; + if (i) + { + old_startup_hook = rl_startup_hook; + rl_startup_hook = set_initial_text; + initial_text = i; + } ret = readline (p); rl_attempted_completion_function = old_attempted_completion_function; if (ret == 0) -- .----------------------------------------------------------------------. | Kevin Pulo Quidquid latine dictum sit, altum viditur. | | [EMAIL PROTECTED] _ll l_ng__g_e_ _r_ hi__ly p__d_ct__le. | | http://www.kev.pulo.com.au/ God casts the die, not the dice. | `--------------- Linux: The choice of a GNU generation. ---------------' _______________________________________________ Bug-bash mailing list Bug-bash@gnu.org http://lists.gnu.org/mailman/listinfo/bug-bash