Skip to content

Commit

Permalink
Update README to include most all utils, and remove some other stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
kata198 committed Jun 4, 2017
1 parent 749f76c commit c20fa00
Showing 1 changed file with 151 additions and 33 deletions.
184 changes: 151 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,186 @@ Advanced commands to extend SH/Bash shell scripting into a more powerful languag
These commands are very fast, and simply replace really advanced, ugly, and errorprone chaining of commands with simple keywords that read easily.


Conditional Evaluation
======================
Full List of Programs
---------------------

The following commands add more advanced testing facilities, and are expected to be use in conditionals (if).
**aslist** - Converts input to a space-separated variable. Input is either as arguments, or if no arguments frmo stdin

For the isin/notin series of commands, the return value is "0" if the statement is true, "1" if not true, or a value > 127 if an error occured that prevented the test from being performed.
So, doing the following at the start of your program will easily make your program accept arguments on commandline for on stdin

ARGS=$(aslist $@)

**isin**

Takes a value on stdin. Returns true (0) if any of the arguments matches that value exactly. Otherwise, retuns false (1).
**bgtask** - Runs a task in the background

if echo "--help" | isin $@;
**cout** - Collate all input before output. Use this, for example, to write back to a file being read, e.x. "sort fname | cout fname" -- It will collect all output from the 'sort' pipe, THEN open the file (whereas a builtin-redirect is opened before execution, so you'll end up with a null file)


**dirnamen** - Discovers information about the Nth parent directory. First argument is the directory name, second is number of levels.

output is two lines, the first line is the dirname N levels up (so 1 is parent directory, 2 is parent-of-parent, etc), and second line is the popped dirname.

Example:

[tim glibc]$ pwd # Show current directory
/usr/src/arch/glibc

[tim glibc]$ dirnamen "`pwd`" 2 # Get information two-levels-up
/usr/src
arch


**echoerr** - Shortcut to echo to stderr

**nmtmp** - Generate a timed temporary file with a given key and optional timeout.

First arg is the key (you make one up specific to application), second is optional and timeout (default 60 seconds).

After timeout, file will automatically be deleted.

Prints filename on stdout, so you can gather like:

MYNAME="$(nmtmp myprog 360)" # Generate a temp file with key 'myprog' that deletes after 360 seconds and store filename in $MYNAME

Useful with gtmp

**gtmp** - Get the last temporary name created by nmtmp with a given key.

**isdigit** - Test if argument is a digit.

if ( ! isdigit "${ARG}" );
then
echoerr "Argument must be an integer. Got: ${ARG}"
fi

**isfloat** - Test if an argument is a floating point number (may contain decimal)

**isempty** - Check if a file is empty. Works with stdout and exit code, see --help

**isin** - Reads value on stdin, and tests if any of the args match it.

if ( echo "${ARG}" | isin "-h" "--help" "-?" );
then
printUsage;
exit 1;
fi

The above example script checks if any of the arguments ($@) was "--help".
**isin_nocase** - Same as *isin*, but case-insensitive

**notin** - Reads value on stdin, and tests that it does NOT match any of the args

**isin\_nocase**
if ( echo "${ARG}" | notin "-a" "-b" "-c" "-d" );
then
echoerr "Invalid argument: ${ARG}";
fi

Same as isin, but case insensitive.
**notin_nocase** - Same as *notin*, but case-insensitive

**notin**
**listContains** - First argment is needle, remainder is haystack. Checks if needle is in haystack.

Takes a value on stdin. Returns true (0) if that value is not present as any of the given arguments.
if ( listContains "--help" "$@" );
then
printUsage;
fi

(echo "error" | notin $RESULTS1 $RESULTS2) && doSuccess;
**stripstr** - Strip whitespace from left and right side of a string

The above script checks if the word "error" occurs in either of the strings $RESULTS1 or $RESULTS2. If it does not, "doSuccess" is called.
[tim ~]$ STRIPPED="$(stripstr " Hello World ")"

**notin\_nocase**
[tim ~]$ printf "'%s'\n" "${STRIPED}"
'Hello World'

Same as notin, but case insensitive..
**lstripstr** - Strip the left side of a string

[tim ~]$ echo " Hello world" | lstripstr
Hello world

Performance
===========
**rstripstr** - Strip the right side of a string

Tools are written in C, and only do their direct job.
**noecho** - Run command without output

Here is a benchmark on an unloaded system, showing 42x+ (.001s is rounded up) speed for a simple match. On a loaded system, this could be much higher:
**prefixitems** - First argument is prefix, and remainder are strings to which the prefix will be prepended. -l to out one-per-line.

[tim shell-advancedutils]$ time ( echo "--help" | ./bin/isin "--help" "abc" "arg3" ); echo "Result: $?"
[tim ~]$ prefixitems -l "Cheese_" "one" "two" "three"
Cheese_one
Cheese_two
Cheese_three

real 0m0.001s
user 0m0.000s
sys 0m0.000s
Result: 0
**printferr** - Shortcut to printf to stderr

**prompt** - Prompt for user input, and keep displaying prompt until input matches against a provided list of valid input

[tim shell-advancedutils]$ time (echo "--help" | python -c 'import sys; x = sys.stdin.read().split(); sys.exit(int(not bool("--help" in sys.argv[1:])))' --help abc arg3); echo "Result: $?"
[tim ~]$ DO_CONTINUE="$(prompt 'Continue? (y/n): ' 'y' 'Y' 'n' 'N')"
Continue? (y/n): hello
Continue? (y/n): bad
Continue? (y/n): input
Continue? (y/n): n
[tim ~]$ echo ${DO_CONTINUE}
n

real 0m0.042s
user 0m0.027s
sys 0m0.013s
Result: 0
**readall** - Reads all input from stdin into a variable, multiple-lines. Kind of like "cat --", but includes escaping options. See --help

**sortByCol** - Sorts input on stdin based on a 1-origin column number. See --help for options.

Error Messages
==============
[tim ~]$ ps auxh | sortByCol --int 2 # Sorts output by second column (pid), to display all processes in ascending order by PID

**splitContains** - Split a string by a token, and determine if any of the resulting elements match a needle. NOTE: Args start with --% and that is NOT a typo, that is so you can test args without overlap.

if ( splitContains "${AND_ARGS}" '&' 'ARG_MAGIC' );
then
HAS_ARG_MARGIC=1
else
HAS_ARG_MAGIC=0
fi

**strerror** - Takes an error code ( $? ) and converts it to the POSIX-defined string for that number. Many numbers have no defined meaning, and programs can use any exit code they want (supposed to use in the unassigned range for their own meanings, but many programs don't. )

Example:

do_something;
RET=$?

if [ ${RET} -ne 0 ];
then
printferr "Got error executing 'do_something': Error %s\n" "$(strerror ${RET})"
fi

Output:

Got error executing 'do_something': Error 24 - Too many open files

**strlen** - Takes input either on stdin or on arguments. Use this instead of wc -c, because this behaves better with terminal applications. i.e. it does not count the trailing newline if there is one.

See the potential off-by-one error below:

Expect "abc" to have strlen of 3:

[tim ~]$ echo "abc" | wc -c # WRONG!
4
[tim ~]$ echo "abc" | strlen # RIGHT!
3

Show that newlines ARE counted if found inside the string:

[tim ~]$ echo -e "abc\ndef" | wc -c
8
[tim ~]$ echo -e "abc\ndef" | strlen
7


**te** - Performs a test (via /bin/test), but outputs "true" or "false" in addition to having exit code. This is useful in some circumstances.

[tim ~]$ IS_EQUAL=$(te 1 -eq 2)
[tim ~]$ echo "${IS_EQUAL}"
false

**teq** - "te" QUIET. Not sure why I wrote this, it's basically same as "test"


**sau-activate.sh** - This file is automatically added to /etc/profile.d and will be sourced for interactive sessions. It implements several functions. TODO: Document these


Error Messages (strerror)
========================

Ever get a return code from an application, like 52, and not know what the hell that means?

Expand Down

0 comments on commit c20fa00

Please sign in to comment.