-2

My objective is to make a bash script service that creates a file when the runlevel is 5 and delete that file when the runlevel is 3.

The problem that I got is when i got to runlevel 3 . I get :

The current lvl is : 3 and number of arguments is : 1 I am at line 10 . The command is start

Why it's getting start argument and I didn't pass any argument.
Function start is for creating the file and function stop is for deleting the file and they are working fine
I can make the script work fine if I remove the test condition on the number of arguments and let the script just delete the file when it's at lvl 3

but the thing that it tells me that the number of argument is 1 and it starts doesn't enter my mind. I have already done much research and I didn't find any solution.

#! /bin/bash
# chkconfig: 35 99 01
# description : some startup script

#### Constants
FILE="/home/ayadi/Desktop/inittp"
CURRENT_LVL="$(runlevel | awk '{print $2}')"
echo "The current lvl is : $CURRENT_LVL and number of arguments is : $# "
echo "I am at line 10 . The command is $1"

#### Functions
start(){
    if ! [[ -f "$FILE" ]];
    then
    touch "$FILE"
    echo "File Created..."
    else
    echo "File Does Exist..."
    fi
}
stop(){
    if [[ -f "$FILE" ]];
    then
    rm "$FILE"
    echo "File Deleted..."
    else
    echo "File Does Not Exist..."
    fi
}

#### Main

if [ $# -eq 0 ]
then
    echo "Entred the arguments -eq 0"
    if [ "$CURRENT_LVL" == "5" ]
    then
        echo "Entred the if current lvl 5 statement"
        start
    fi
    if [ "$CURRENT_LVL" == "3" ]
    then
        echo "Entred the if current lvl 3 statement"
        stop
    fi

else

case "$1" in
    [sS][tT][aA][rR][tT])
        if  ! ([ -e "$FILE" ])
        then
        echo "I am the case statement.the command is $1"
        start
        fi
        ;;
    [sS][tT][oO][pP])
        if [ -e "$FILE" ]
        then
        stop
        fi
        ;;
    *)
        echo "Please enter start or stop"
        ;;
esac

fi
Community
  • 1
  • 1
Tahero
  • 328
  • 4
  • 11
  • 2
    Also, the parens in `! ([ -e "$FILE" ])` have a significant performance cost (they instruct the shell to create a subprocess and run the test in there). Cheaper to take them out: `[ ! -e "$FILE" ]` or `! [ -e "$FILE" ]` will work just as well. – Charles Duffy Oct 14 '18 at 23:37
  • 1
    As for the question itself, though -- we can't reproduce that with only what you've provided. It's not just the script itself that matters, but also how it's invoked. – Charles Duffy Oct 14 '18 at 23:38
  • (As another aside -- in `[ ]`, the only POSIX-standard string comparison operator is `=`, not `==`; the latter will work in bash specifically, but it's not reliable across all POSIX shells). – Charles Duffy Oct 14 '18 at 23:39
  • (...and another aside: all-caps variable names are reserved for variables meaningful to the shell itself or to other POSIX-specified tools, whereas names with at least one lower-case character are guaranteed safe for application use; see http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, fourth paragraph; following this guidance avoids breaking your shell by inadvertently overriding meaningful variables like `PATH`). – Charles Duffy Oct 14 '18 at 23:40
  • @CharlesDuffy I was making TEMPORARY="~" because I wanted to delete the temporary file later. Sorry I forgot to remove it. – Tahero Oct 14 '18 at 23:43
  • ...really, though, I wouldn't ever advise anyone to use an inittab-based runlevels in new code. Modern Linux distros will have something more capable -- runit, systemd, upstart, etc. `ExecStart=/usr/bin/touch /home/ayadi/Desktop/inittp` and `ExecStop=/usr/bin/rm /home/ayadi/Desktop/inittp` with `Type=oneshot`, and there you are. – Charles Duffy Oct 14 '18 at 23:44
  • That said, assuming that you *are* going to stick with the current approach -- you're changing runlevels with `telinit` or something like it, right? If so, your init system is then responsible for calling things that need to be started or stopped with `start` or `stop` arguments; you shouldn't be inspecting `CURRENT_LVL` in the script at all, but instead relying on the calling process to feed an appropriate instruction. – Charles Duffy Oct 14 '18 at 23:47
  • @CharlesDuffy Thank you for your comments they provided me so many new information. I thought it's best practice to write Variables in UPPERCASE. Really thank you. you asked how the script is invoked, I added the script as a service using chkconfig --add script_name and now it's on the runlevel 3 and 5 . when i go to run level 3 it says that there is an argument passed to the scritp but I didn't pass any argument – Tahero Oct 14 '18 at 23:49
  • When you say "go to run level 5", do you mean you're running `telinit 5`? **That** (indirectly) passes the argument. – Charles Duffy Oct 15 '18 at 00:01
  • @CharlesDuffy Yes I am using `init 3` to go to level 3 – Tahero Oct 15 '18 at 00:08
  • @CharlesDuffy If I write `init 3` at terminal. How does that indirectly passed the argument? and why it passed the strat argument, not the stop argument? – Tahero Oct 15 '18 at 00:10
  • So, err, yeah. Your distro's init scripts are calling your script, and... why do you expect that they won't pass any arguments? Adding `start` or `stop` arguments is their *job*. – Charles Duffy Oct 15 '18 at 00:10
  • It's a "start" for `init 3` because 3 -- like 5 -- is in the list given at `# chkconfig: 35 99 01` as a level at which the service is supposed to be started. – Charles Duffy Oct 15 '18 at 00:11
  • @CharlesDuffy
    as I know fro my knowledge ( I am totally a beginner at bash script) that if I write this command `./script_name`
    it will run the script without passing any argument. and that script will show that number of arguments id 0. but when I that bash script service run automatically at run level 3 it does call the start function . I didn't understand how this phenomen work . and again thank you for your time and attention.
    – Tahero Oct 15 '18 at 00:16
  • @CharlesDuffy the service is supposed to get started at lvl 3 and 5 without getting any arguments – Tahero Oct 15 '18 at 00:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/181851/discussion-between-tahero-and-charles-duffy). – Tahero Oct 15 '18 at 00:26

2 Answers2

1

Debugging advice, change from this:

echo "The current lvl is : $CURRENT_LVL and number of arguments is : $# "
echo "I am at line 10 . The command is $1"

To this:

echo "The current lvl is : $CURRENT_LVL and number of arguments is : $# "
echo "I am at line 10 . The command is \"$1\", the whole command line is \"$0 $@\""

This won't solve the problem, but it'll provide more information on what's really going on.


#Main can be simplified. It won't solve anything, but it'll make it easier to think about:

#### Main

case "${1,,}" in
    "")     echo "Entered no arguments."
            case "$CURRENT_LVL" in
              3|5) echo "Entered the if current level ${CURRENT_LVL} statement" ;;&
              5)   start ;;
              3)   stop ;;
            esac  ;;

    start)  if ! [ -e "$FILE" ] ; then
                echo "I am the case statement.the command is $1"
                start
            fi ;;

    stop)   [ -e "$FILE" ] && stop ;;

    *)      echo "Please enter start or stop" ;;
esac

Note the bashisms. ${1,,} returns $1 in lower case. ;;& drops to the next case test, rather than jumping to ecase.

agc
  • 7,973
  • 2
  • 29
  • 50
0

By default, when a service is called to run automatically at a specific run level, it's assigned with "start" argument.

Tahero
  • 328
  • 4
  • 11