Showing posts with label shell. Show all posts
Showing posts with label shell. Show all posts

Thursday, 24 May 2018

crond runs /bin/sh not /bin/bash

Got caught by this today. Cron jobs normally run /bin/sh, not /bin/bash. It's probably required POSIX behaviour.

Normally most commands run out of cron are not affected because they are not dependent on bash, or the shell script starts with #!/bin/bash. However commands like vncserver which start up desktops (e.g. with the @reboot time spec) can be sensitive to the shell used because of environment scripts in /etc/profile.d.

Therefore if you want to ensure that the cron job works the same whether run interactively or from a crontab, specify the shell. E.g.

@reboot SHELL=/bin/bash /usr/bin/vncserver ...

Saturday, 23 July 2016

"$@" is a shell idiom

TL;DR: Use "$@" when you want to pass arguments unchanged to a function or program.

When you read the shell documentation you will see that there are two main ways to refer to all the arguments for passing to a function or program: $* and "$@". What is the difference? This test script will demonstrate it:

#!/bin/sh

testargs() {
       echo testargs: $# arguments
       showargs $*
       showargs "$@"
}

showargs() {
       echo showargs: $# arguments
       for i
       do
               echo $i
       done
}

testargs 1 2 3
testargs word 'quoted phrase' word

The result should be:
testargs: 3 arguments
showargs: 3 arguments
1
2
3
showargs: 3 arguments
1
2
3
testargs: 3 arguments
showargs: 4 arguments
word
quoted
phrase
word
showargs: 3 arguments
word
quoted phrase
word
As you can see, the difference is manifest when an argument has whitespace. "$@" preserves the arguments, not parsing it again to break up at whitespace in arguments. Think if it as an idiom meaning pass arguments verbatim.

Why would you ever use $* though? Here's a place where you shouldn't use "$@".
su -c "$*" user
If you were to use "$@" and it contained multiple arguments, only the first argument would be used by -c and the others would follow, causing a syntax error. This however means that if you want to pass arguments with whitespace to -c, you have to quote them and escape the quotes too.

Wednesday, 28 November 2012

cd to directory containing a file

Many times I have run a program on a file and then immediately, wanted to change to the directory containing it, to do more operations. For example:
vim path/to/some/dir/file
then I next want to do:
cd path/to/some/dir
I used to do
cd !$
and then use the up arrow key to get the previous failed command to edit out the trailing filename and re-execute. Then I decided I should write a shell alias or function to do this. It has to be an alias or a function and not a script as cd needs to work in the current shell.

This is what I came up with:
cdf() { cd ${1%/[^/]*}; }
This uses the remove matching suffix operation of parameter substitution, see the bash manual page for details. So now I can do:
cdf !$
and I will end up in the directory containing the file I just worked on.

I picked cdf as an abbreviation for change to directory of file, but you may prefer some other name.