Showing posts with label The Shell Programming Language. Show all posts
Showing posts with label The Shell Programming Language. Show all posts

Wednesday, December 18, 2013

shell code and useless use of "ls *.tar"

Consider this code (I came across such Korn shell script code recently):
TARFILE=$(ls -1 /tmp/*.tar)
According to http://partmaps.org/era/unix/award.html#ls you ought to replace the ls with a glob, e.g. like this:
[[ -s /tmp/*.tar ]] && set -A tarfiles /tmp/*.tar
for TARFILE in "${tarfiles[@]}"
do
  : # ...
done
Instead you may want to enquire ${#tarfiles[@]}, i.e. the number of files globbed.

Please forgive me the naming here! I was happy to take this note anyway.

Wednesday, November 13, 2013

migrated a Korn shell script using "Extended Pattern Matching" to bash

https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html

I had to "shopt -s extglob" for that.

I inserted the shopt line rather close to the case statement, where the Extended Pattern Matching gets employed. That was inside a loop. That had no effect, but it didn't say so. I rather threw some weird error messages. I reduced the code around the causing line to its minimum, occasionally moved the shopt to outside the loop, and it worked. If it had only been that straigt …

Tuesday, November 5, 2013

the bash's "nullglob" is rather nice to use

http://www.gnu.org/software/bash/manual/html_node/Filename-Expansion.html

w/o this command line:
$ shopt -s nullglob
a glob pattern, that does not successfully evaluate to existing file names, gets literally resolved to a file name identical to the glob pattern.
With the above command line executed already, this command line will print file infos of /etc/passwd and ignore the unsuccessful other two glob patterns:
$ ll /etc/passwd /etc/passwd? /etc/passwd??
In interactive mode you may want to see the error messages, within a shell script supplying all three parameters to a "for f in …" loop, you will want the unresolving ones to get ignored.
$ for f in /etc/passwd /etc/passwd? /etc/passwd??; do echo $f; done
Well, at least in my script today I found this option rather useful.

I tried to find something comparable in the Korn Shell, but I wasn't successful.

Wednesday, February 20, 2013

O'Reilly Media book: bash Pocket Reference

bash Pocket Reference:
You need to know how to work with the bash shell if you want to get to the heart of Unix systems, including Linux and Mac OS X. Now covering the most recent version of bash, this concise little book puts all of the essential information about bash at your fingertips. You'll quickly find answers to annoying questions that always come up when you're writing shell scripts -- What characters do you need to quote? How do you get variable substitution to do exactly what you want? How do you use arrays? -- and much more.

O'Reilly Media book: bash Cookbook

bash Cookbook - O'Reilly Media

O'Reilly Media book: Learning the bash Shell, 3rd Edition

Learning the bash Shell, 3rd Edition - O'Reilly Media

Wednesday, October 17, 2012

shell: basename and dirname through Parameter Expansion


If you want to have basename and dirname a little faster through shell builtins, you may want to try these in bash or Korn Shell:
  • basename: ${file##*/}
  • dirname: ${file%/*}
I don't really recommend to use these substitutes, I still find basename and dirname quite readable and I am not using them in a loop anyway.

Saturday, October 6, 2012

O'Reilly Media book: Learning the Korn Shell, 2nd Edition

Q: The ksh on "your" AIX – is it ksh88 or ksh93?
A: Well … the ksh on "my" AIX knows the "whence" builtin without "-a", so I think it's a ksh88, because ksh93 would know "whence -a".
(This paragraph will go to another article on ksh. (TBD))

Sunday, August 12, 2012

O'Reilly Media book: Classic Shell Scripting




nice scripts shown there and available in the sample code:
  • pathfind.sh – rather similar to my own find_file_on_PATH.sh
  • show-identical-files.sh – rather similar to my own group_by_content.sh – but has a problem with "md5sum"
  • puser.sh



Wednesday, July 20, 2011

shell programming: "for" loops vs. "while" loops and scope of variables created within loop bodies

Variables, that you create (by assignment) within loop bodies, are well visible outside the loop body. This is valid for both kinds of loop.

CAVEAT:
If the "while" loop reads from a pipe, the "while" loop is executed within a subshell, i.e. the scope of the variables within the loop ends with the loop.

Example:
x=a
echo hello |
while read l
do
  x=b
done
echo "x=$x"

What's the output of this echo?
x=a
Example:

x=a
for l in hello
do
  x=b
done
echo "x=$x"


What's the output of this echo?
x=b

Friday, July 9, 2010

want to get signalled, when a command line job on your computer is done?

I have a long list of cpanm jobs,
don't want to put them in a batch all toghether,
and want  to get signalled, when each of them is done:
$ while true; do beep; done
In my case the beep is acutally just the flashing of an xterm window.

Update:
Yes, notify-send is far, far, far superiour, growlnotify on OS X.
Thanks for the pointers!

GNU Coreutils "seq"

the manual page.

Why do I keep forgetting the name of this wonderful little helper?


seq prints a sequence of numbers to standard output. Synopses:
     seq [option]... last
     seq [option]... first last
     seq [option]... first increment last
seq prints the numbers from first to last by increment. By default, each number is printed on a separate line. When increment is not specified, it defaults to ‘1’, even when first is larger than lastfirst also defaults to ‘1’. So seq 1 prints ‘1’, but seq 0 and seq 10 5 produce no output. Floating-point numbers may be specified (using a period before any fractional digits).

best practices in shell script programming – colons

My snipplet for an if/then/else in shell scripts looks like this:
if true
then :
else :
fi
The colons make that code syntactically complete, w/o the colons you run into a syntax error. The colon is the "null op" of (Bourne) shell scripting.
And the colons usually remain there for the remainder of the life of that code.
Have you noticed, that the youngsters, that talk about snipplets nowadays seriously think, they invented them? True, I guess, they created the term. Just the term.

best practices in shell script programming – double quotes


You do know the result of this:
a=A; echo $a
But are you just as sure here?
a=A; b=B; echo $a.$b
That depends on the shell, you are using. So I suggest you better write it this way:

a=A; b=B; echo ${a}.${b}
Enclosing variable names in curly braces is quite often a good idea.

Look at the following piece of code:
case $var in
  x*)
    echo var starts with x
    ;;
  *)
    echo var starts with something else
    ;;
esac
Looks alright, doesn't it?
No, it's does not. If that variable had not been assigned a value before or is of zero length, you will see an ugly syntax error occur.
Therefore enclose the variable in double quotes like here:
case "$var" in
  x*)
    echo var starts with x
    ;;
  *)
    echo var starts with something else
    ;;
esac
There is no good excuse for not doing it anywhere. It may look ugly and unnecessary, but it will help. That's the way shell scripting is. I learned this from Jürgen Gulbins around 1987, when I enjoyed working for him. This series of articles is dedicated to him. I owe him a lot.

best practices in shell script programming

You do know the result of this:
a=A; echo $a
But are you just as sure here?

a=A; b=B; echo $a.$b
That depends on the shell, you are using. So I suggest you better write it this way:


a=A; b=B; echo ${a}.${b}
Enclosing variable names in curly braces is quite often a good idea.

Friday, July 2, 2010

App::perlbrew - Manage perl installations in your $HOME or wherever you want

Prerequisites:
  • $ zypper install patch
  • $ zypper install gcc
Caveat:
  • yes, "perlbrew install" occasionally and too often  needs "--force" and even "--notest", don't be too surprised! my "5.14.2" and also my "5.16.1" needed it

Main links:

$ export PERLBREW_ROOT=/opt/perlbrew
$ curl -kL http://install.perlbrew.pl | bash
# or maybe like this:
$ perlbrew self-upgrade


The developer/maintainer does not have in mind this use case as the main use case!! But it is my main use case.
What to do after installing a new perl, that you consider your new stable perl?
$ perlbrew alias create perl-RELEASE stable 
# resp.
$ perlbrew alias -f create perl-RELEASE stable
# use this shebang line with $PERLBREW_ROOT expanded [Link]:
#! $PERLBREW_ROOT/perls/stable/bin/perl

$ perlbrew switch stable # this will be our usual starting point!!!
 
# but "perlbrew list-modules" does not work on such an alias, so "perlbrew use" to a non-alias before!


  • Have a serious look at "$ perlbrew help" once in a while!!!



I decided to make use of $PERLBREW_ROOT, as I want to keep my home $HOME minimial, just data and scripts, no big files, they all go to other disks. And right, my home directory is on an encrypted partition, and this sort of stuff certainly does not get encrypted.
$ export PERLBREW_ROOT=/usr/local/perlbrew
Therefore my perlbrew is installed as:
/usr/local/perlbrew/bin/perlbrew
They suggest, that my $HOME/.bashrc should "source" their .../etc/bashrc, but for the time being I let my $HOME/.profile do this, as IMHO this is right place.
So actually this is according to best practices for shell programming the right way (for me) to do it, and now this code is of course included in my $HOME/.profile:


# for perl's App::perlbrew :
export          PERLBREW_ROOT=/usr/local/perlbrew # on my Linux boxes
export          PERLBREW_ROOT=/sw/perlbrew # on my Mac box(es)
source         $PERLBREW_ROOT/etc/bashrc
##export  PATH=$PERLBREW_ROOT/bin:$PERLBREW_ROOT/perls/current/bin:${PATH}
path_prepend   $PERLBREW_ROOT
path_prepend   $PERLBREW_ROOT/perls/current


BTW: always "$ hash -r" after switching, so you avoid getting certain perl resp. perlbrew related error messages like this one and a few others (confusion of the right installation directory):
bash: …: No such file or directory
I successfully brewed 5.10.1 and 5.12.1 on openSUSE-11.2, but on OS X Snow Leopard I only brewed 5.12.1 successfully, brewing 5.10.1 failed.


To be continued …


Update 2011-10-16:
On my Mac running Lion I was able to perlbrew these releases of perl


  • perl-5.15.3 and
  • perl-5.14.2
  • but not perl-5.12.4, 5.10.1, 5.8.9, 5.6.2

but that seems more than sufficient to me.

Looks like OS X got targeted as a serious platform for perl development only rather recently.


Update 2012-10-07: A historic note: I first looked into perlbrew in the context of "biz-JG".