1. 20
  1.  

  2. 7
    1. pushd / popd vs ‘cd -‘

    A word of caution on the use of pushd/popd in scripts: keep their uses close together or you can get very lost. I prefer using subshells for this sort of thing since, when the subshell is finished, the environment (including the current working directory) is restored.

    1. source vs ‘.’

    One thing not mentioned here is how source will find things. From the reference manual:

    If filename does not contain a slash, the PATH variable is used to find filename. When Bash is not in POSIX mode, the current directory is searched if filename is not found in $PATH.

    It’s generally a good idea to always use a full or relative path to a file being sourced (that is, something with a slash in it) or you could be in for some real surprises.

    1. 4

      […] I prefer using subshells for this sort of thing […]

      I’d usually go with putting cds into a shell-function, rather than spawning a subshell.

      Mostly because it’s for my taste easier to read, argue and test.

      modify files
      create directory
      ( cd directory
      run something
      )
      proceed in original pwd
      

      vs.

      run_something() {
        [ -d "$1" ] || _error "dir missing $1"
        cd "$1"
        run something
      }
      
      modify files
      create directory
      run_something directory
      proceed in original pwd
      

      I guess it might also help with trap-statements.

      1. 5

        Hrm, I don’t think that will work.

        #!/bin/bash 
        
        run_something() {
            cd tmp
        }
        
        echo "${BASH_VERSION[*]}"
        echo "Before: " $(pwd)
        run_something
        echo "After: " $(pwd)
        

        When I run it:

        % ./tmp/t.sh 
        4.4.19(1)-release
        Before:  /home/woz
        After:  /home/woz/tmp
        
        1. 4

          Oh, wow - thank you for checking. Can’t reproduce what I gave as an earlier example either.

          Sorry for my misinformation, can’t check my scripts at my old employer anymore - maybe I wrapped it into a function and still used a subshell (which contradicts my criticism).

          I guess I’d go then with using a subshell inside a function, but still doesn’t make my earlier statement more correct.

          #!/bin/bash 
          
          run_something() {
              (
                  cd tmp
              )
          }
          
          echo "${BASH_VERSION[*]}"
          echo "Before: " $(pwd)
          run_something
          echo "After: " $(pwd)
          
      2. 4

        A word of caution on the use of pushd/popd in scripts: keep their uses close together or you can get very lost.

        I tend to favour push/pop, but I also use indentation to help match them up, e.g.

        mkdir foo
        pushd foo
          bar baz quux
        popd
        
      3. 6

        This is a intermediate-level list of things you want to know about bash.

        Sidenote: I read every “bash tips” post. Many are for beginners. I propose subtags in the titles, like [beginner], [intermediate], and [advanced].

        1. 5

          Regarding extended glob, they give glob syntax the power of regular expressions. They are not used often in normal shell scripts, but they are used heavily in bash completion scripts.

          In most cases, you can read them like regular expressions with prefix rather than postfix repetition operators, e.g. +(foo|bar) is like the regex (foo|bar)+.

          This post explains a bit how completion scripts are almost like their own dialog of bash:

          https://lobste.rs/s/mu9nc5/running_bash_completion_scripts_with_osh#c_d7wjv2

          I’m looking for help on this bug if you really want to get past syntax and into the theory of regular expressions:

          https://github.com/oilshell/oil/issues/192