3

Good day. I have a series of commands that I wanted to execute via a function so that I could get the exit code and perform console output accordingly. With that being said, I have two issues here:

1) I can't seem to direct stderr to /dev/null.

2) The first echo line is not displayed until the $1 is executed. It's not really noticeable until I run commands that take a while to process, such as searching the hard drive for a file. Additionally, it's obvious that this is the case, because the output looks like:

sh-3.2# ./runScript.sh
sh-3.2# com.apple.auditd: Already loaded
sh-3.2# Attempting... Enable Security Auditing ...Success

In other words, the stderr was displayed before "Attempting... $2"

Here is the function I am trying to use:

#!/bin/bash
function saveChange {
    echo -ne "Attempting... $2"
    exec $1
    if [ "$?" -ne 0 ]; then
        echo -ne " ...Failure\n\r"
    else
        echo -ne " ...Success\n\r"
    fi
}

saveChange "$(launchctl load -w /System/Library/LaunchDaemons/com.apple.auditd.plist)" "Enable Security Auditing"

Any help or advice is appreciated.

Taelo
  • 55
  • 1
  • 4

2 Answers2

2

this is how you redirect stderr to /dev/null

command 2> /dev/null

e.g.

ls -l 2> /dev/null

Your second part (i.e. ordering of echo) -- It may be because of this you have while invoking the script. $(launchctl load -w /System/Library/LaunchDaemons/com.apple.auditd.plist)

Bill
  • 5,263
  • 6
  • 35
  • 50
  • Hi Bill, thanks that worked great. I was trying to redirect to /dev/null from within the function, instead of from the command that was to be executed. Do you have any advice or input on my second question? – Taelo May 09 '13 at 13:16
  • You can do this -- `exec $1 2> /dev/null` – Bill May 09 '13 at 13:16
  • Why do you `$` in your first argument? Any reason? If you just want to pass the entire string to the script, you can do `launch.......` and `$1` should pick up everything. – Bill May 09 '13 at 13:19
  • Bill, that doesn't seem to work. If I move the redirect down to the function call,... $(launchctl load -w /System/Library/LaunchDaemons/com.apple.auditd.plist 2> /dev/null) ... it works as expected. – Taelo May 09 '13 at 13:19
  • I was reading that I can use $(command) instead of ` command `. I thought it looked cleaner to use $() instead of the backticks. – Taelo May 09 '13 at 13:21
  • You are passing this as an arg, so when you invoke the function, this is not a command, just a string....when you do `exec $1` then it gets executed. So, I would say it is cleaner to just have `launch......` and get rid of `$` in that argument. Does this work better? – Bill May 09 '13 at 13:22
  • Hi Bill, thanks for your help. I had to enclose the command, launchctl load -w /System/Library/LaunchDaemons/com.apple.auditd.plist, in backticks for it to execute. I still have the issue of the command executing before the echo output, but I guess I can live with it. – Taelo May 09 '13 at 13:41
  • @Taelo I am not sure I understand exactly what you have in your script. This is an example of how I will be passing arguments which are commands. `function hello { echo "$2"; exec $1; echo "done"; } hello "ls -l" "abc"` ... please note that when I am passing `ls -l` to my function, I do not have `$` or `\``. I just pass it as another string, `ls -l`, and `exec` takes care of executing it. Hope this helps. – Bill May 09 '13 at 14:08
  • I am passing in commands as arguments to the function saveChange. For example: `saveChange(chmod -N /usr/sbin/cron)` `saveChange(find /var/audit -type f -exec chown root {} \;)` `saveChange(sed -i '' -E '/(tty_tickets.*|timestamp_timeout.*)/d' /etc/sudoers)` and alot more. – Taelo May 09 '13 at 17:48
1

The first echo line is displayed later because it is being execute second. $(...) will execute the code. Try the following:

#!/bin/bash
function saveChange {
    echo -ne "Attempting... $2"
    err=$($1 2>&1)
    if [ -z "$err" ]; then
        echo -ne " ...Success\n\r"
    else
        echo -ne " ...Failured\n\r"
        exit 1
    fi
}

saveChange "launchctl load -w /System/Library/LaunchDaemons/com.apple.auditd.plist" "Enable Security Auditing"

EDIT: Noticed that launchctl does not actually set $? on failure so capturing the STDERR to detect the error instead.

marcoseu
  • 3,892
  • 2
  • 16
  • 35
  • Hi Marcoseu, no this does not appear to work. bash -x displays the command correctly, but it's not executing. – Taelo May 09 '13 at 13:31
  • Removed the exec from sample code to make this script run. I just found out that launchctl actually does not set the $?. Will post another answer to tackle that. – marcoseu May 09 '13 at 14:37
  • Thanks that works; however, I still don't get the first echo output until $1 has completed its execution. Is there any way I can stop that behavior? When I pass a string in to execute that takes a while to complete, I just get a blank line. When the command finishes, I get both echo statements at the same time. – Taelo May 09 '13 at 15:46
  • I just replaced the `launchctl...` to `sleep 3` and I do get `Attempting... Enable Security Auditing` then `Success` comes 3 seconds later. Are you using the sample code I posted above? – marcoseu May 09 '13 at 16:04