Hi All, Below are some issues I found with history substitution. I am duplicating its behavior in a somewhat different use, and found issues with the documentation and bugs as described.
Jim Monte From: jim To: bug-bash@gnu.org Subject: Issues with history substitution and its documentation Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='l$ uname output: Linux T5500-Ubuntu 4.18.0-22-generic #23~18.04.1-Ubuntu SMP Thu J$ Machine Type: x86_64-pc-linux-gnu Bash Version: 4.4 Patch Level: 19 Release Status: release Description: ============================================================================= Documentation of quick substitution is incorrect (or does not match behavior). I believe this issue is an error with the documentation of history "Quick Substitution" that has existed since the first snapshot available at web.archive.org in 2007 at https://web.archive.org/web/20071223174140/http://www.gnu.org/software/bash/manual/html_node/Event-Designators.html At the least it is true that bash does not behave as the documentation states, but it does act in a way that is more reasonable (to me) than what is written. The documentation states that ^string1^string2^ is equivalent to !!:s/string1/string2/. However, bash treats it as equivalent to !!:s^string1^string2^. jim@T5500-Ubuntu:~$ echo /a /a jim@T5500-Ubuntu:~$ ^/a^b^ echo b b jim@T5500-Ubuntu:~$ echo /a /a jim@T5500-Ubuntu:~$ !!:s//a/b/ echo ab/ ab/ jim@T5500-Ubuntu:~$ echo /a /a jim@T5500-Ubuntu:~$ !!:s^/a^b^ echo b b ============================================================================= Behavior of empty "old" string in a substitution is undefined. The earlier example also shows a related but different issue with the !!:s//a/b/ command, where the string to locate is empty. It causes /a to be replaced by a and the b/ is appended. But jim@T5500-Ubuntu:~$ echo ///a ///a jim@T5500-Ubuntu:~$ !!:s//z/ echo //z //z Here the empty string caused /a to be replaced by z. However, jim@T5500-Ubuntu:~$ echo ///abcdefg ///abcdefg jim@T5500-Ubuntu:~$ !!:s//z/ echo //zbcdefg //zbcdefg Here a slash and the first character of the second word are replaced by z. jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:s//z/ echo z b c z b c jim@T5500-Ubuntu:~$ echo /// /// jim@T5500-Ubuntu:~$ !!:s//z/ bash: :s//z/: substitution failed Using :gs instead of :s does not change the results. ============================================================================= BUG If an event designator has a leading - character, it is ignored. jim@T5500-Ubuntu:~/tmp$ cat main.c #include <stdio.h> int main(void) { (void) fprintf(stdout, "Hello, world!\n"); return 0; } jim@T5500-Ubuntu:~/tmp$ gcc main.c -o"-a" jim@T5500-Ubuntu:~/tmp$ gcc main.c -o"-b" jim@T5500-Ubuntu:~/tmp$ -a Hello, world! jim@T5500-Ubuntu:~/tmp$ !-a:s/a/b bpt-cache abc ============================================================================= Documentation of the :h and :t modifiers in section 9.3.3 is incomplete. :h removes the last / and everything after it if a / is present. Otherwise it does nothing. :t removes everything before and including the last / if one is present. Otherwise it does nothing. If a slash is present, !!:h/!!:t is equivalent to !!. jim@T5500-Ubuntu:~$ echo /a/b/c/d /a/b/c/d jim@T5500-Ubuntu:~$ !!:h echo /a/b/c /a/b/c jim@T5500-Ubuntu:~$ echo /a/b/c/d /a/b/c/d jim@T5500-Ubuntu:~$ !!:h:h echo /a/b /a/b jim@T5500-Ubuntu:~$ echo /a/b/c/d /a/b/c/d jim@T5500-Ubuntu:~$ !!:h:h:h echo /a /a jim@T5500-Ubuntu:~$ echo /a/b/c/d /a/b/c/d jim@T5500-Ubuntu:~$ !!:h:h:h:h echo jim@T5500-Ubuntu:~$ jim@T5500-Ubuntu:~$ echo /a/b/c/d /a/b/c/d jim@T5500-Ubuntu:~$ !!:t d d: command not found jim@T5500-Ubuntu:~$ echo a/b a/b jim@T5500-Ubuntu:~$ !!:h/!!:t echo a/b a/b jim@T5500-Ubuntu:~$ echo a/b a/b jim@T5500-Ubuntu:~$ !! echo a/b a/b ============================================================================= Documentation of the :r and :e modifiers is incomplete. :r removes the last ".suffix" and everything after it, if a ".suffix" is present. Otherwise it does nothing. :e leaves the last ".suffix" and everything after it, if a ".suffix" is present. Otherwise it does nothing. jim@T5500-Ubuntu:~$ echo .suffix a b .suffix c d .suffix a b .suffix c d jim@T5500-Ubuntu:~$ !!:r echo .suffix a b .suffix a b jim@T5500-Ubuntu:~$ echo .suffix a b .suffix c d .suffix a b .suffix c d jim@T5500-Ubuntu:~$ !!:r:r echo jim@T5500-Ubuntu:~$ echo .suffix a b .suffix c d .suffix a b .suffix c d jim@T5500-Ubuntu:~$ !!:e .suffix c d jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:r echo a b c a b c jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:e echo a b c a b c ============================================================================= BUG :p does not suppress execution if it is duplicated. jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:p echo a b c jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:p:p echo a b c a b c ============================================================================= Documentation of :q and :x is incomplete. If :q and :x are repeated, the last specification is taken. jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:q 'echo a b c' echo a b c: command not found jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:x 'echo' 'a' 'b' 'c' a b c jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:q:x 'echo' 'a' 'b' 'c' a b c jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:q:x:q 'echo a b c' echo a b c: command not found jim@T5500-Ubuntu:~$ echo a b c a b c jim@T5500-Ubuntu:~$ !!:q:x:q:x 'echo' 'a' 'b' 'c' a b c ============================================================================= Finally, documentation of G should mention that it can be used with both :s and &.