67 Matching Annotations
  1. Aug 2022
    1. $0 would be OK in most cases, some exceptions are, for instance, when the script you're executing is aliased (through alias in .bash_profile). You should really use $BASH_SOURCE variable, instead of $0.
    2. Using $0 does not work when the script is run using source script or . script; the name of the script is not available.
  2. Jul 2022
    1. Always use a while read construct: find . -name "*.txt" -print0 | while read -d $'\0' file do …code using "$file" done The loop will execute while the find command is executing. Plus, this command will work even if a file name is returned with whitespace in it. And, you won't overflow your command line buffer.
  3. Jun 2021
    1. Please make sure that your file(s) referenced in bin starts with #!/usr/bin/env node, otherwise the scripts are started without the node executable!
    1. Since looping over the positional parameters is such a common thing to do in scripts, for arg defaults to for arg in "$@". The double-quoted "$@" is special magic that causes each parameter to be used as a single word (or a single loop iteration). It's what you should be using at least 99% of the time.
    2. Bash (like all Bourne shells) has a special syntax for referring to the list of positional parameters one at a time, and $* isn't it. Neither is $@. Both of those expand to the list of words in your script's parameters, not to each parameter as a separate word.
    1. Instead of using a for loop, which will fail on spaces unless you redefine the IFS variable, I would recommend using a while loop combined with find.
    1. Different ways to prepend a line: (echo 'line to prepend';cat file)|sponge file sed -i '1iline to prepend' file # GNU sed -i '' $'1i\\\nline to prepend\n' file # BSD printf %s\\n 0a 'line to prepend' . w|ed -s file perl -pi -e 'print"line to prepend\n"if$.==1' file
    1. for cpp_file in *.cpp; do gcc -c $$cpp_file & done; wait This gives much finer control than make -j.
    2. There is one very important reason for enabling job control to be useful inside scripts: the side-effect it has of placing background processes in their own process groups. This makes it much, much easier to send signels to them and their children with one simple command: kill -<signal> -$pgid. All other ways of dealing with signaling entire trees of processes either involve elaborate (sometimes even recursive) functions, which are often bugnests, or risk killing the parent in the process (no pun intended).
    1. To avoid the problems with different versions of echo you may want to use printf instead. In contrast to echo printf always interprets \ sequences but doesn't automatically add a linefeed at the end so you have to append \n at the end if you want one.
    1. while (( "$#" )); do case "$1" in -a|--my-boolean-flag) MY_FLAG=0 shift ;; -b|--my-flag-with-argument) if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then MY_FLAG_ARG=$2 shift 2 else echo "Error: Argument for $1 is missing" >&2 exit 1 fi ;; -*|--*=) # unsupported flags echo "Error: Unsupported flag $1" >&2 exit 1 ;; *) # preserve positional arguments PARAMS="$PARAMS $1" shift ;; esacdone# set positional arguments in their proper placeeval set -- "$PARAMS"
  4. May 2021
    1. For filter-branch, using pipelines like git ls-files | grep -v ... | xargs -r git rm might be a reasonable workaround but can get unwieldy and isn't as straightforward for users; plus those commands are often operating-system specific (can you spot the GNUism in the snippet I provided?)
  5. Apr 2021
    1. Write stderr and stdout to a file, display stderr on screen (on stdout) exec 2> >(tee -a -i "$HOME/somefile.log") exec >> "$HOME/somefile.log" Useful for crons, so you can receive errors (and only errors) by mail
    2. I just wanted to point out that the syntax is not supported by the POSIX standard and thus won't universally work in /bin/sh scripts (many people erroneously use bash syntax in /bin/sh scripts)
    3. exec > >(tee "$HOME/somefile.log") 2>&1
    1. When you have a pipeline, unbuffer must be applied to each element except the last (since that doesn't have its output redirected). Example: unbuffer p1 | unbuffer p2 | unbuffer p3 | p4
    1. empty is an utility that provides an interface to execute and/or interact with processes under pseudo-terminal sessions (PTYs). This tool is definitely useful in programming of shell scripts designed to communicate with interactive programs like telnet, ssh, ftp, etc.
    2. can be easily invoked directly from shell prompt or script

      Can't expect / unbuffer / etc. (whatever this is attempting to contrast itself with) be easily invoked directly from shell prompt or script too??

      Okay, I guess you have to know more about how expect is invoked to understand what they mean. One glance at the examples, comparing them, and all becomes clear:

      empty -f -i in -o out telnet foo.bar.com
      empty -w -i out -o in "ogin:" "luser\n"

      I didn't realize that expect required/expected (no pun intended) to be used in scripts with its own shebang line:

      spawn telnet foo.bar.com 
      expect ogin {send luser\r}

      That does make it less easy/normal to use expect within a shell script.

      I was coming to the expect project from/for the unbuffer command, which by contrast, is quite easy to include/use in a shell script -- almost the same as empty, in fact. (Seems like almost a mismatch to have unbuffer command in expect toolkit then. Or is expect command the only odd one out in that toolkit?)

    3. does not use TCL, Perl, PHP, Python or anything else as an underlying language is written entirely in C has small and simple source code can easily be ported to almost all UNIX-like systems
  6. Mar 2021
  7. Feb 2021
    1. Now this probably won't make difference in the real world (e.g. because the exit codes are not portable and on top of that not always unambiguous as discussed in Default exit code when process is terminated?)
    1. The parentheses always start a subshell. What's happening is that bash detects that sleep 5 is the last command executed by that subshell, so it calls exec instead of fork+exec. The sleep command replaces the subshell in the same process.
  8. Nov 2020
    1. The potential problem: if second_task fails, third_task will not run, and execution will continue to the next line of code - next_task, in this example. This may be exactly the behavior you want. Alternatively, you may be intending that if second_task fails, the script should immediately exit with its error code. In this case, the best choice is to use a block - i.e., curly braces: first_task && { second_task third_task } next_task Because we are using the -e option, if second_task fails, the script immediately exits.
    2. When people write COND && COMMAND, typically they mean "if COND succeeds (or is boolean true), then execute COMMAND. Regardless, proceed to the next line of the script." It's a very convenient shorthand for a full "if/then/fi" clause.
    1. It starts truncating it's output (shortening strings with ...) once you pipe it's output into grep. That is quite unacceptable. When I am checking if something is inhibited in a script, I should have all possible information available and not have to consider if a string will get truncated when being piped into a tool, that is perfectly readable on a wide terminal.
  9. Oct 2020
  10. Jun 2020
  11. May 2020
    1. I have used this bash one-liner before set -- "${@:1:$(($#-1))}" It sets the argument list to the current argument list, less the last argument.

      Analogue of shift built-in. Too bad there isn't just a pop built-in.

  12. Apr 2020
    1. Invert the exit code of a process. Make 0 into 1 and everything else into a 0. An alternative to ! some-command syntax present in some shells.
  13. Feb 2020
  14. Dec 2019
    1. As for exec, I am just using it because it makes sense to run the final command in the same process, replacing the wrapper script instead of spawning a new process. It's not strictly necessary.
  15. Nov 2019
  16. Sep 2019
  17. Feb 2017
    1. A shell script is a file of executable commands that has been stored in a text file. When the file is run, each command is executed.

      The power of BASH!