You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3.6 KiB

BASH Notes

basename

Don't use basename, use:

  file=${path##*/}

dirname

Don't use dirname, use:

  dir=${path%/*}

shopt

If you set shopt in a function, reset to its default state with trap:

func() {
  trap "$(shopt -p nullglob globstar)" RETURN
  shopt -q -s nullglob globstar
}

find, grep, print0, -0, -z

Don't use find in for loops, because filenames can contain spaces. Try to use globstar and nullglob or null byte terminated strings.

Instead of:

func() {
    for file in $(find /usr/lib* -type f -name 'lib*.a' -print0 ); do
      echo $file
    done
}

use:

func() {
    trap "$(shopt -p nullglob globstar)" RETURN
    shopt -q -s nullglob globstar

    for file in /usr/lib*/**/lib*.a; do
      [[ -f $file ]] || continue
      echo "$file"
    done
}

Or collect the filenames in an array, if you need them more than once:

func() {
    trap "$(shopt -p nullglob globstar)" RETURN
    shopt -q -s nullglob globstar

    filenames=( /usr/lib*/**/lib*.a )

    for file in "${filenames[@]}"; do
      [[ -f $file ]] || continue
      echo "$file"
    done
}

Or, if you really want to use find, use -print0 and an array:

func() {
    mapfile -t -d '' filenames < <(find /usr/lib* -type f -name 'lib*.a' -print0)
    for file in "${filenames[@]}"; do
      echo "$file"
    done
}

Note: -d '' is the same as -d $'\0' and sets the null byte as the delimiter.

or:

func() {
    find /usr/lib* -type f -name 'lib*.a' -print0 | while read -r -d '' file; do
      echo "$file"
    done
}

or

func() {
    while read -r -d '' file; do
      echo "$file"
    done < <(find /usr/lib* -type f -name 'lib*.a' -print0)
}

Use the tool options for null terminated strings, like -print0, -0, -z, etc.

prefix or suffix array elements

Instead of:

func() {
  other-cmd $(for k in "$@"; do echo "prefix-$k"; done)
}

do

func() {
  other-cmd "${@/#/prefix-}"
}

or suffix:

func() {
  other-cmd "${@/%/-suffix}"
}

Join array elements with a separator char

Here we have an associate array _drivers, where we want to print the keys separated by ',':

    if [[ ${!_drivers[*]} ]]; then
        echo "rd.driver.pre=$(IFS=, ;echo "${!_drivers[*]}")" > "${initdir}"/etc/cmdline.d/00-watchdog.conf
    fi

Optional parameters to commands

If you want to call a command cmd with an option, if a variable is set, rather than doing:

func() {
  local param="$1"

  if [[ $param ]]; then
    param="--this-special-option $param"
  fi

  cmd $param
}

do it like this:

func() {
  local param="$1"

  cmd ${param:+--this-special-option "$param"}
}

# cmd --this-special-option 'abc'
func 'abc'

# cmd
func ''

# cmd
func

If you want to specify the option even with an empty string do this:

func() {
  local -a special_params

  if [[ ${1+_} ]]; then
    # only declare `param` if $1 is set (even as null string)
    local param="$1"
  fi

  # check if `param` is set (even as null string)
  if [[ ${param+_} ]]; then
    special_params=( --this-special-option "${param}" )
  fi

  cmd ${param+"${special_params[@]}"}
}

# cmd --this-special-option 'abc'
func 'abc'

# cmd --this-special-option ''
func ''

# cmd
func

Or more simple, if you only have to set an option:

func() {
  if [[ ${1+_} ]]; then
    # only declare `param` if $1 is set (even as null string)
    local param="$1"
  fi

  cmd ${param+--this-special-option}
}

# cmd --this-special-option
func 'abc'

# cmd --this-special-option
func ''

# cmd
func