LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   ATTN: Code ninjas, need help with bash script (https://www.linuxquestions.org/questions/linux-newbie-8/attn-code-ninjas-need-help-with-bash-script-4175465024/)

mreff555 06-06-2013 03:58 PM

ATTN: Code ninjas, need help with bash script
 
I want to us the time command to run and time multiple commands and output them to a log file. how can I do this? I've tried quite a lot

The problem right now is two fold. I thought this should work to at least output the time to the screen, but no luck.
Code:

time {$CONFIGCOMMAND \
      $MAKECOMMAND \
      $INSTALLCOMMAND \
    }


AlucardZero 06-06-2013 04:22 PM

time bash -c "commands"

Or put the commands in a script

Code:

$ time sh -c "sleep 1; sleep 1; sleep 1"

real        0m3.037s
user        0m0.002s
sys        0m0.008s


thedaver 06-06-2013 04:23 PM

time { ls; ls -l; df; w; }

mreff555 06-06-2013 07:43 PM

Great, thanks guys, now what if I wanted to output this time to a log file. I've tried playing with pipes and redirects but I keep sending the output of the command to the file rather than the output of the time.

chrism01 06-07-2013 01:46 AM

Looks ugly but ...
Code:

(time (ls && ls) ) >t.t 2>&1
Ensures output first from all cmds, then timing at end of output file.

mreff555 06-07-2013 07:39 AM

Interesting, that may be exactly what I need.

David the H. 06-07-2013 08:41 AM

First, what are $CONFIGCOMMAND, $MAKECOMMAND, and $INSTALLCOMMAND? I hope these aren't variables that contain complex commands.

I'm trying to put a command in a variable, but the complex cases always fail!
http://mywiki.wooledge.org/BashFAQ/050

Variables are for holding data, not code. If you want to simplify a complex command, define it in a function first.


Second, in the OP code '\' at the end of the line means to continue the command on the next line. So what you were really trying to run is this:

Code:

time { $CONFIGCOMMAND $MAKECOMMAND $INSTALLCOMMAND }
That would be a single command with at least two arguments. To make it work as desired, each individual command needs to be separated by either a solid newline or ';'.

Although, also, the command grouping syntax is wrong. when the opening and closing brackets are on a single line, the closing bracket also needs to be separated by a semicolon (as a built-in shell keyword, it's treated like a command.)

Either of these would work (discounting my first point):

Code:

time { $CONFIGCOMMAND ; $MAKECOMMAND ; $INSTALLCOMMAND ; }

time { $CONFIGCOMMAND
      $MAKECOMMAND
      $INSTALLCOMMAND
    }

You can then redirect the output of the entire grouping as shown above.

Command Grouping

Edit:
Reading a bit closer, if you want to capture the output of time, but not the commands, we have to define the redirections for the commands properly. This will probably require a second, oustide, grouping.


Code:

{ time

    {
        $CONFIGCOMMAND
        $MAKECOMMAND
        $INSTALLCOMMAND
    } >/dev/tty 2>&1

} 2>outfile.txt

time outputs to stderr, so we need to capture (2) to the file.

The inner redirection sends both the stdout and stderr of the inner commands directly to the terminal, so that any error messages from them don't go to the output file. You could also just send everything to /dev/null and eliminate all output.

mreff555 06-07-2013 12:37 PM

Thanks, that clears up quite a bit.

I tried your command and it works, however it seems to also work leaving out the inner redirection.

As for the variables, they aren't exactly small, but probably no larger than a path variable or variables used in typical slack builds. I guess I could try turning it in to a function. What is the disadvantage to using variables for large strings?

David the H. 06-09-2013 04:16 AM

Simple text strings, of any length, are fine. Recommended even.

It's only trying to contain actual commands and shell syntax in variables, and expecting the shell to execute them later, that's discouraged. When I see a variable with the name "$CONFIGCOMMAND", and you're using it without an echo or some other command name in front of it, that tells me you're probably trying to do something like that.

Again, a shell variable is structure designed for containing data, not code. Use functions for long and complex commands. See the link I gave before.

mreff555 06-10-2013 10:10 AM

After I replied to you the other day I decided you were correct and it made more sense to treat these command lines as functions rather than variables.
It works great except for one thing. It seems to make it even more difficult to redirect something to output. For example a function like this

Code:

function config {...}
function make {...}

...
...
time {
      config
      make
}

runs the two functions and outputs the time at the end. It seemed that your methods described should work the same as with variables, however they don't.
No matter what I try redirecting output to a text file only creates an empty file.

I tried it with a simple function, in which the output I wanted was to stdout and still had the same problem. for example

Code:


function hello {
    echo "This is a test"
}

hello >> outputfile

This creates and empty file but does not write to it. What is different about a function that causes this?

David the H. 06-11-2013 12:24 PM

There's no reason I can see why that shouldn't work. Functions take file descriptors and redirections just like any other command. Your "hello" function works for me as written.

Do note that function is a bash/ksh keyword, and isn't available in posix-compliant shells. Use "hello()" instead to define functions in the most portable way.

ksh, by the way, supports both patterns, but apparently treats them slightly differently. Although to my understanding this mostly affects variable scoping. Check its documentation if that's the shell you're using. bash treats both the same.

Also be sure that you're using the proper shebang at the top of your script. #!/bin/sh is your system's posix-compliant shell. If you want to (reliably) use bash features in your script, be sure to use #!/bin/bash there specifically.


All times are GMT -5. The time now is 11:20 PM.