1. 32
  1.  

  2. 18

    I used bash for years and learned some of these, but when I realised I could ‘set -o vi’ or use .inputrc to do the same, I quickly forgot them.

    Now if I’m in bash or zsh or fish, I can reproduce the functionality in the given examples with esc j and then vi operations on that previous line. Probably a similar number of keystrokes, but I get to use my vi muscle memory and I don’t have to learn how to use every shell’s particular way of doing things.

    1. 6

      Yeah ditto. I use !$ and !! and !123, and set -o vi for everything else.

      Though I implemented a few more options in Oil’s bash-compatible history, like !foo, because they were easy. I’m interested in feedback on history – the latest release is at https://oilshell.org/ as always.

      Honestly I think a TUI selecting commands would be better than history then !123. Typing the numbers feels pretty ancient, although I’ve gotten used to it. I don’t do Ctrl-R because I feel like it increases the probability of calling up an errant rm command and destroying work.

      1. 4

        zsh has hist_verify, which shows the result of history replacements/substitutions, and makes you hit enter again before execution. Seems like a nice middle ground between “blind” and TUI.

    2. 13

      I stopped counting after 10 ads. Why did you do that?

      1. -10

        Ads? Where there supposed to be ads in the article? Verily, there must be something wrong with my systems in that they always seem to ‘forget’ showing such ‘content’. Maybe I should have another look at…

        • that blocklist on the router…
        #!/bin/sh
        
        DNSSERVER=10.1.1.1
        CUSTOM_WHITELIST=/etc/hosts.white
        CUSTOM_BLACKLIST=/etc/hosts.block
        TMPDIR=$(mktemp -d|sed -e 's/\///')
        
        SOURCES="
          http://mvps.org/winhelp2002/hosts.txt
          http://www.malwaredomainlist.com/hostslist/hosts.txt
          http://hosts-file.net/ad_servers.txt
          http://adaway.org/hosts.txt
        "
        
        if [ -s $CUSTOM_BLACKLIST ]; then
        	cp $CUSTOM_BLACKLIST /$TMPDIR/hosts.black
        fi
        
        echo "localhost" >  /$TMPDIR/hosts.white
        if [ -s $CUSTOM_WHITELIST ]; then
        	cat $CUSTOM_WHITELIST >> /$TMPDIR/hosts.white
        fi
        
        for s in $SOURCES; do
        	wget -qO- $s | grep '^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | sed -r 's/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}[\t ]*//' >> 
        /$TMPDIR/hosts.black
        done
        
        cat /$TMPDIR/hosts.black | sed 's/\s*#.*$//; s/^[\t ]*$//; s/\r$//' | grep -vF /$TMPDIR/hosts.white | sort | uniq | awk '{ print "'$DNSSERVER' " $1 }' > /etc/
        hosts.black
        
        # semi-safe removal, if TMPDIR is empty only /tmp gets clobbered instead of /
        rm -rf /tmp/$(echo $TMPDIR|sed -e 's/tmp\///')
        
        killall -HUP dnsmasq
        
        • that ipset based firewall on the same router…
        # create ipsets if they don't exist yet
        if ! ipset list|grep ETip; then ipset create ETip hash:ip; fi
        if ! ipset list|grep ETcidr; then ipset create ETcidr hash:net; fi
        if ! iptables -L ETBLOCKLIST; then iptables -N ETBLOCKLIST; fi
        if ! iptables -L LOGNDROP; then iptables -N LOGNDROP; fi
         
        if ! iptables -L input|grep -q ETBLOCKLIST; then
          iptables -I INPUT 1 -j ETBLOCKLIST
        fi
         
        if ! iptables -L forward|grep -q ETBLOCKLIST; then 
          iptables -I FORWARD 1 -j ETBLOCKLIST               
        fi
        
        if [ $(iptables -L ETBLOCKLIST|wc -l) -lt 4 ]; then                  
          iptables -F ETBLOCKLIST                                            
          iptables -A ETBLOCKLIST -m set --match-set ETip src,dst -j LOGNDROP
          iptables -A ETBLOCKLIST -m set --match-set ETcidr src,dst -j LOGNDROP
        fi                                                                    
         
        if [ $(iptables -L LOGNDROP|wc -l) -lt 6 ]; then
          iptables -F LOGNDROP
          iptables -A LOGNDROP -p tcp -m limit --limit 5/min -j LOG --log-prefix "Denied TCP: " --log-level 7
          iptables -A LOGNDROP -p udp -m limit --limit 5/min -j LOG --log-prefix "Denied UDP: " --log-level 7
          iptables -A LOGNDROP -p icmp -m limit --limit 5/min -j LOG --log-prefix "Denied ICMP: " --log-level 7
          iptables -A LOGNDROP -m limit --limit 5/min -j LOG --log-prefix "Denied OTHTYPE: " --log-level 7
          iptables -A LOGNDROP -j REJECT
        fi
        
        # flush sets
        ipset flush ETip
        ipset flush ETcidr
         
        tmp=$(mktemp)
         
        wget -q http://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt -O "$tmp"
        
        cat /etc/custom-block-ip >> "$tmp"
         
        lines=$(wc -l "$tmp"|cut -f1 -d" ")
        currentline=0
         
        exec <"$tmp"
         
        read line
        while [ $currentline -lt $lines ]; do
          read line
          if echo "$line" | egrep -q "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"; then
            ipset -q -! add ETip "$line"
          fi
          if echo "$line" | egrep -q "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{2}$"; then
           ipset -q -! add ETcidr "$line"
          fi
          currentline=$(expr $currentline + 1)
        done
         
        rm "$tmp"
        
        • that uBlock Origin thing in my browser

        The problem must be found somewhere there.

        1. 3

          Even with an adblocker, there’s a couple of breaks in the content to advertise a course and a book. Not traditional ads, but still a nuisance. I don’t this site is getting a whole lot out of using ads because most of its target market uses an adblocker. What we probably forget is that ads are still a somewhat viable option for a little passive income on sites with non-technical users.

          1. 2

            Delightful, but could you perhaps move this over to some Github gists or something so as to take up less space here?

        2. 13

          Can anyone explain what’s the whole point in using any of these if you can just use the up arrow key, and the shortcut to get to the start of the line (ctrl-a), to edit the previous line from history as-is? (FreeBSD’s bindkey -k up history-search-backward in tcsh is also great; I configure all my systems for this.) Seems like a much easier thing to do. I’ve literally never had to use any of these ! shortcuts, not even !! (why would you — it’s more typing than just the up key), and it’s really annoying when they occasionally expand in quotes and such.

          The only useful one I found is !#:1.bak, as in, cp file !#:1.bak, and even then it’s such a mouthful yet is still mostly pointless, as it’ll take a while to learn, and simply doing cp file{,.bak} is so much easier and more straightforward (plus, if you need to change the original file, by going back to history, you’ll only need to change a single copy of it with the {,bak} version, whereas the !#:1.bak version will now have two copies of the original parameter for you to amend, as the expansion happens prior to the history).

          In all, pretty much every single one of these bang shortcuts is pretty useless, even for someone like me who stays the whole day in the shell, and does all sorts of snippets for just about everything, from lynx, curl, grep, sed and awk to sort and uniq. Maybe these bang shortcuts were useful in the 1970s or 1980s, or whenever the terminals were really dumb, and/or bandwidth was really scarce, but I can’t find much value in any of these nowadays, nor anywhere within the last 20 years or so.

          1. 1

            Regarding !!, I use it a few times a day.

            Example one:

            sebboh@geeks ~$ head -1 /etc/shadow
            head: cannot open '/etc/shadow' for reading: Permission denied
            sebboh@geeks ~$ sudo !!
            sudo head -1 /etc/shadow
            Password: 
            root:!:18044::::::
            sebboh@geeks ~$ 
            

            Example two:

            sebboh@geeks ~$ which less
            /run/current-system/profile/bin/less
            sebboh@geeks ~$ ls -al `!!`
            ls -al `which less`
            lrwxrwxrwx 2 root root 61 Dec 31  1969 /run/current-system/profile/bin/less -> /gnu/store/ivwkw1s2siab38wswhmkms2qpinzmyx8-less-530/bin/less
            sebboh@geeks ~$ 
            

            (Actually, normally I’d use `!!` to invoke an editor.. But less is probably a binary, so in this contrived example, it didn’t make sense for me to open it for editing. Maybe some grep -l invocation would have made a better example…)

            I hope you find these useful! BTW, I count ctrl+a as two keys.. ;)

          2. 12

            I’ve disabled these completely a long time ago, because bang-shortcuts work even in quoted strings, so

            git commit -m "it finally works!"
            

            would run my previous rm * or whatever command instead.

            Alt+. (Meta+.) prints the last arg of the last command.

            1. 3

              That seems horrible. Does anyone know if zsh suffers from the same problem? And, if so, how to disable it?

              1. 2

                It does. I use single-quotes as a work-around.

            2. 10

              I can’t bring myself to executing things that I don’t see the full expansion of before execution. These would all be great if I could customize bash to prompt me with the expansion and y/n. Otherwise, I don’t think I’d risk trying. It’s the same reason I don’t even use !!.

              1. 6

                zsh will expand these on <Tab>. So try typing !!<Tab>.

                1. 4

                  I use !!, but only to sudo a command. Otherwise I agree - it’s a touch too easy to mess things up.

                  1. 2

                    For history commands, you can always append a “:p” to the end to only print the command and not execute it. It inserts it into your history too, so you can !! and execute it after viewing it.

                    $bash> echo a
                    a
                    $bash> ls
                    file1 file2
                    $bash> !e:p
                    echo a
                    $bash> !!
                    a
                    

                    The “!e:p” command will only print the last command that started with an ‘e’; it won’t execute it. Because it’s now in the history, !! actually executes it.

                  2. 2

                    Escape then . gets you the last argument in your prompt.

                    1. 2

                      And, if your Alt key works in your terminal, you can use Alt+. instead. This is universal: all your Alt+ key combos may be achieved with Esc instead and vice versa.

                    2. 1

                      I found one improvement for myself and one for the article.

                      I had no idea !!:1 should be shortened to !:1.

                      !:1-$ is better expressed as !*. This may seem more specific, but it seems more commonly useful like the !$ that takes top billing in the article.

                      (I use zsh.)