Shell scripting notes
From raju
piping into a braced block
The idea here is iterate over a bunch of items by sending them as input into a while block.
$svn log -q foo.py --limit 10 | grep -E -e "r[[:digit:]]+" -o | { > while read r > do > echo $r > done > } r377 r362 r360 r350 r334 r330 r275 r244
Ref:- https://stackoverflow.com/a/283168/6305733
read each line of a file in a for loop
Approach 1:
$while read r do echo $r done < /path/to/file
Approach 2:
$cat /path/to/file | while read r do echo $r done
Check if a word exists in an array
Consider
$ DAYS=(sun mon tue wed thu fri sat)
Create an auxiliary variable with the string to be matched as a regex. So to match the word "tue", do
$ TODAY="\btue\b" $ [[ ${DAYS[@]} =~ $TODAY ]] && echo 1 || echo 0 1
where '\b' denotes the word boundary.
You can check that '\b' really works. For example
$ TODAY="tu" $ [[ ${DAYS[@]} =~ $TODAY ]] && echo 1 || echo 0 1 $ TODAY="\btu\b" $ [[ ${DAYS[@]} =~ $TODAY ]] && echo 1 || echo 0 0
shows that there is a string "tu" in DAYS but not the word "tu". Similarly
$ TODAY="n m" $ [[ ${DAYS[@]} =~ $TODAY ]] && echo 1 || echo 0 1 $ TODAY="\bn m\b" $ [[ ${DAYS[@]} =~ $TODAY ]] && echo 1 || echo 0 0
shows that there is a string "n m" some where in DAYS but not as a word.
Alternatively, you can use command line substitution instead of creating an extra variable
$ [[ ${DAYS[@]} =~ $(echo "\btue\b") ]] && echo 1 || echo 0 1 $ [[ ${DAYS[@]} =~ $(echo "\btu\b") ]] && echo 1 || echo 0 0 $ [[ ${DAYS[@]} =~ $(echo "\bmon\b") ]] && echo 1 || echo 0 1 $ [[ ${DAYS[@]} =~ $(echo "\bn m\b") ]] && echo 1 || echo 0 0
However, do not use string literals for this. It can match simple strings but not the word boundaries.
$ [[ ${DAYS[@]} =~ "\btue\b" ]] && echo 1 || echo 0 0 $ [[ ${DAYS[@]} =~ "tue" ]] && echo 1 || echo 0 1 $ [[ ${DAYS[@]} =~ "n m" ]] && echo 1 || echo 0 1
Tested on Debian Stretch (9.3) with
$ bash --version GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2016 Free Software Foundation, Inc.
Ref:-
- https://stackoverflow.com/questions/9792702/does-bash-support-word-boundary-regular-expressions
- https://linux.die.net/man/1/bash - search for "binary operator, =~"
tags | checking for word boundaries, regex, "=~" operator, equal tilde operator in shell scripts
Difference between * and @ in bash arrays
Consider
$ DAYS=(sun mon tue wed thu fri sat)
If you do ${DAYS[@]}, ${DAYS[*]} then there is no difference.
$ for i in ${DAYS[@]}; do echo $i; done sun mon tue wed thu fri sat $ for i in ${DAYS[*]}; do echo $i; done sun mon tue wed thu fri sat
But it makes a difference if they are enclosed in quotes. For example, "${DAYS[@]}" expands to seven words as "sun" "mon" "tue" "wed" "thu" "fri" "sat. But "${DAYS[*]}" expands to a single word "sun mon tue wed thu fri sat"
$ for i in "${DAYS[@]}"; do echo $i; done sun mon tue wed thu fri sat $ for i in "${DAYS[*]}"; do echo $i; done sun mon tue wed thu fri sat
Interactively test a condition in a shell
This will return 1 if foo.txt exists, 0 otherwise.
[[ -f foo.txt ]] && echo 1 || echo 0
To see how it works
[[ "SUNDAY" == "SUNDAY" ]] && echo 1 || echo 0 1 [[ "SUNDAY" == "Sunday" ]] && echo 1 || echo 0 0 [[ "SUNDAY" == "SUN" ]] && echo 1 || echo 0 0 [[ "SUNDAY" == "MONDAY" ]] && echo 1 || echo 0 0
Call perl script from shell
Create the shell script as follows. It is basically a pass through for the perl function.
=> cat hello #! /bin/tcsh -f ~/work/perl/from_shell_script/hello.pl $*
Now create a simple perl script that dumps its arguments.
=> cat hello.pl #! /usr/bin/perl -w use strict; use warnings; use Data::Dumper qw(Dumper); print Dumper \@ARGV;
Run the perl program
=> ./hello.pl -a -b raju $VAR1 = [ '-a', '-b', 'raju' ];
Same as above except that we use the shell wrapper.
=> ./hello -a -b raju $VAR1 = [ '-a', '-b', 'raju' ];
Shell expands the arguments before passing it to the calling scripts.
=> ls hello* hello.pl* => ./hello hello* $VAR1 = [ 'hello', 'hello.pl' ]; => ./hello "hello*" $VAR1 = [ 'hello', 'hello.pl' ]; => ./hello 'hello*' $VAR1 = [ 'hello', 'hello.pl' ];
Specify a default if not initialized on command line
% cat foo.sh #! /bin/bash output=${1:-kama raju `date +'%Y%m%d_%H%M%S'`} echo $output % chmod +x foo.sh % foo.sh kama raju 20180316_101112 % foo.sh foo foo % foo.sh foo bar foo % foo.sh "foo bar" foo bar
Ref:-
- https://www.cyberciti.biz/faq/bash-ksh-if-variable-is-not-defined-set-default-variable/
- https://stackoverflow.com/questions/2013547/assigning-default-values-to-shell-variables-with-a-single-command-in-bash
useful links
- https://www.linuxjournal.com/content/return-values-bash-functions - Talks about how to return Values from bash functions