0

I want to understand this code since I am a beginner in shell scripting

1  #!/bin/bash
2 PATH=$PATH:/bin:/usr/bin
3
4
5 TMP_FILE=/tmp/i_am_running
6 [ -f $TMP_FILE ] && exit
7 touch $TMP_FILE
8
9
10 /usr/bin/python /home/ahmed/Desktop/python.py
11 rm $TMP_FILE
  1. Why do we use line 1 and 2?
  2. I have just learned if then else structure

    if then fi

cant we convert line 6-7 in that structure?

1

4 Answers 4

1

I'll go line by line:

1: This appears to be a defect: there should be no whitespace before the #. Anyway it's a "shebang line" which tells what interpreter to use. Some people would prefer to see #!/usr/bin/env bash which gives more flexibility if users want to run under a non-default version of bash.

5: Create a variable containing a path.

6: [ -f $TMP_FILE ] && exit means "If the file exists, exit (with success code, i.e. 0)." You are right that it could be written as an "if" statement. Also note that [ -f $TMP_FILE ] is actually shorthand for test -f $TMP_FILE; knowing this you can look at man test to see what the various options are.

7: Now that we know the file does not exist, we create it. Or at least we try to--this could fail for various reasons, and the return code is not checked! It is good practice to put set -e at the top of any shell script, which means "stop if there is an unchecked failure code."

10: Next we run Python. Not the user's choice of Python interpreter, but specifically the one is /usr/bin/. Again this is not best practice--best would be to have a #!/usr/bin/env python shebang line at the top of the Python script itself, and invoke it directly, allowing the user's environment to select the desired Python interpreter.

11: Now we remove $TMP_FILE, which would allow us to run again next time. Therefore it's a sort of "lock file," though not a very robustly implemented one. For example, what happens if the user interrupts the script by pressing Ctrl-C while the Python script is running? The lock file will be left behind. You could use the trap builtin in Bash to remove the lock file before exiting in this case.

Maybe you should just integrate the lock file functionality directly in Python, and get rid of this wrapper script. You can do that by putting this at the top of your Python script, and getting rid of the wrapper completely:

import errno
import fcntl
import sys

lockfile = open('/tmp/i_am_running', 'a')
try:
      fcntl.flock(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError as ex:
      if ex.errno == errno.EWOULDBLOCK:
            sys.exit("oops, already running")
      else:
            raise

# now the file is locked, do whatever you need and it will unlock on exit

Finally, note that the canonical location for lock files like this on Linux systems is under /var/run/, not /tmp/.

Sign up to request clarification or add additional context in comments.

4 Comments

great! i understood very well. Can you modify this concept to deal with the case where the program crashes or the user stops it in between?
Sure, I edited my answer to add some code to make it more robust.
I am sorry but it looks like python. should i make a separate program to avoid crashing problem? can i modify the shell script?
No need for shell script, throw it away. Just put that code at the top of your Python script and it will take care of itself.
1
  1. The first line is a so-called shebang. It tells whatever tries to run the file how to run it. The second line makes sure /bin and /usr/bin are on the $PATH by appending them to that variable, so that running simply command x will work if x is in one of those two directories (or some other directory already in $PATH).

  2. Lines 6 and 7 don't really have anything to do with each other. Line 6 in itself could be turned into an if statement:

    if [ -f $TMP_FILE ]
    then
      exit
    fi
    

1 Comment

@user3265370 It puts a string (that happens to look like a path) in a variable named TMP_FILE. (That variable is used later on.) It sounds like you ought to read a shell scripting tutorial, rather than piling on questions here.
1
1 #!/bin/bash
2 PATH=$PATH:/bin:/usr/bin
3
4
5 TMP_FILE=/tmp/i_am_running
6 [ -f $TMP_FILE ] && exit
7 touch $TMP_FILE
8
9
10 /usr/bin/python /home/ahmed/Desktop/python.py
11 rm $TMP_FILE
  1. First line: specify the interpreter, which means execute using bash
  2. Second line: add /bin and /usr/bin to enviroenment variable PATH, which is not used normally, this may happen because someone remove them from PATH.
  3. 6-7 line: If file /tmp/i_am_running exists, exit. else, create it. see this post. You can use if-else to do this:

    if [ -f "$TMP_FILE" ]
    then
        exit
    fi
    touch "$TMP_FILE"
    
  4. 10-11 line: run program python.py and remove $TMP_FILE

Comments

1

Line 1 should not be indented; the first character should be #. It tells the kernel to execute this program using the named interpreter, /bin/bash in this case. You can specify any executable (not a script) as the interpreter if you wish, within broad limits.

Line 2 is protecting against the absurd; if someone has a PATH setting without /bin and /usr/bin then they're already in some sort of trouble. However, this ensures that they are present. (Note, though, that on Solaris, /bin is a symlink to /usr/bin, so there's no need for both in $PATH, but one or the other should surely be there.)

Yes, you can convert lines 6-7 into:

if [ -f "$TMP_FILE" ]
then exit
fi
touch "$TMP_FILE"

While your chosen lock file name suffices if there's only a single user on the system, it isn't suitable for more widely used programs (two people can't both use the file at once).

You can improve your code by adding trap commands to clean up the temporary file:

trap "rm -f '$TMP_FILE'; exit 1" 0 1 2 3 13 15
…commands…
rm -f "$TMP_FILE"
trap 0

This removes the temporary file if you program crashes or is interrupted.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.