I was trying to write a script to execute a C program and measure the time for execution using time command in Unix.
The script looks like follows
cc /home/pop/Daa/abc.c
r = `time /home/pop/Daa/./a.out`
echo "recursion" $r >> log.txt
cc /home/pop/Daa/xyz.c
d = `time /home/pop/Daa/./a.out `
echo "dynamic" $d >> log.txt
But after executing the script the log.txt file contains only words recursion and dynamic. The time values seem to be missing. But executing time command on the commandline terminal gave the following output
real 0m0.001s
user 0m0.000s
sys 0m0.000s
How can get this output formatted to contain only the 'real' time of execution and written in the log file?
The output of time goes to stderr. You have to redirect it.
TIMEFORMAT=%R
r=$( { time /home/pop/Daa/./a.out; } 2>&1 )
And you can't have spaces around the equal sign. It is preferable to use $() instead of backticks since it's easier to read, there's no confusion with single quotes and it's easier to nest them.
When you assign values to a variable you shouldn't have spaces around the equals sign. For example:
r=`time /home/pop/Daa/./a.out`
If you only want the "real" time, use grep:
r=`time /home/pop/Daa/./a.out | grep real`
or use %e in the time command:
r=`time -f '%e' /home/pop/Daa/./a.out`
Related
I have a script that stores the output of commands, functions, and other scripts in a log file.
I want to avoid capturing user input.
The line that is in charge of storing the output of the commands to a logfile is this one:
$command 2>&1 | tee /dev/tty | ruby -pe 'print Time.now.strftime("[%s] ") if !$stdin.tty?' >> "$tempfile"
If the command is a function or a script that asks for user input and prints out those data, that input is stored in temporary file. I would like to avoid that since I don't want to capture sensible data.
I can't modify the commands, functions that I'm wrapping.
Your command only saves program output, not user input. The problem you're seeing is that the command has chosen to output whatever the user inputs, merging it into its own output that is then obviously logged.
There is no good way around this. Please fix your command.
Anyways. Here's a bad, fragile, hacky way around it:
tempfile=test.txt
command='read -ep Enter_some_input: '
$command 2>&1 |
tee /dev/tty |
python3 -c $'import os\nwhile s:=os.read(0, 1024):\n if len(s) > 3: os.write(1, s)' |
ruby -pe 'print Time.now.strftime("[%s] ") if !$stdin.tty?' >> "$tempfile"
The Python command drops all reads of 3 bytes or less. This aims to remove character by character echo as would happen in the most basic cases of a user typing into readline and similar, while hopefully not removing too much intentional output.
I need to write the time taken to execute this command in a txt file:
time ./program.exe
How can I do in bash script?
I try with >> time.txt but that doesn't work (the output does not go to file and does go to the screen).
Getting time in bash to write to a file is hard work. It is a bash built-in command. (On Mac OS X, there's an external command, /usr/bin/time, that does a similar job but with a different output format and less recalcitrance.)
You need to use:
(time ./program.exe) 2> time.txt
It writes to standard error (hence the 2> notation). However, if you don't use the sub-shell (the parentheses), it doesn't work; the output still comes to the screen.
Alternatively, and without a sub-shell, you can use:
{ time ./program.exe; } 2> time.txt
Note the space after the open brace and the semi-colon; both are necessary on a single line. The braces must appear where a command could appear, and must be standalone symbols. (If you struggle hard enough, you'll come up with ...;}|something or ...;}2>&1. Both of these identify the brace as a standalone symbol, though. If you try ...;}xyz, the shell will (probably) fail to find a command called }xyz, though.)
I need to run more command in more terminal. If I do this:
xterm -xrm '*hold: true' -e (time ./Program.exe) >> time.exe & sleep 2
it doesn't work and tells me Syntax error: "(" unexpected. How do I fix this?
You would need to do something like:
xterm -xrm '*hold: true' -e sh -c "(time ./Program.exe) 2> time.txt & sleep 2"
The key change is to run the shell with the script coming from the argument to the -c option; you can replace sh with /bin/bash or an equivalent name. That should get around any 'Syntax error' issues. I'm not quite sure what triggers that error, though, so there may be a simpler and better way to deal with it. It's also conceivable that xterm's -e option only takes a single string argument, in which case, I suppose you'd use:
xterm -xrm '*hold: true' -e 'sh -c "(time ./Program.exe) 2> time.txt & sleep 2"'
You can manual bash xterm as well as I can.
I'm not sure why you run the timed program in background mode, but that's your problem, not mine. Similarly, the sleep 2 is not obviously necessary if the hold: true keeps the terminal open.
time_elapsed=(time sh -c "./program.exe") 2>&1 | grep "real" | awk '{print $(NF)}'
echo time_elapsed > file.txt
This command should give you the exact time consumed in bash in a desired file..
You can also redirect this to a file usng 2 > file.txt as explained in another reply.
It's not easy to redirect the output of the bash builtin time.
One solution is to use the external time program:
/bin/time --append -o time.txt ./program.exe
(on most systems it's a GNU program, so use info time rather than man to get its documentation).
Just enclose the command to time in a { .. }:
{ time ./program.exe; } 2>&1
Of course, the output of builtin time goes to stderr, thus the needed redirection 2>&1.
Then, it may appear to be tricky to capture the output, let's use a second { .. } to read the command more easily, this works:
{ { time ./program.exe; } 2>&1; } >> time.txt # This works.
However, the correct construct should simply have the capture reversed, as this:
{ time ./program.exe; } >> time.txt 2>&1; # Correct.
To close any possible output from the command, redirect it's output to /dev/null, as this:
{ time ./program.exe >/dev/null 2>&1; } >> time.txt 2>&1 # Better.
And, as now there is only output on stderr, we could simply capture just it:
{ time ./program.exe >/dev/null 2>&1; } 2>> time.txt # Best.
The output from ./program should be redirected, or it may well end inside time.txt.
I have used time command to execute program (like "xxx$ time ./a.out"), with output as follows,
real 0m7.250s
usr 0m10.395s
sys 0m0.026s
What I want to get is 0 and 7.250 as in 0m7.250s. I have tried "awk '{print $2}'", but without success; nothing output there.
PS: I have tried put output of time command to a file by using ">", also without success.
Try:
pax$ tm=$((time sleep 1) 2>&1 | awk '/^real/{print $2}') ; echo $tm
0m1.002s
(substituting your own a.out command of course, sleep 1 was just used for an example).
It creates a subshell for the time command and ensures that its standard error is sent to standard output instead (time specifically outputs its information to standard error so that it's kept separate from normal output of the program it's timing).
The awk command the captures the line starting real and outputs the second argument (the time).
The time command sends its output to standard error, so as not to interfere with normal program output. You will want to use 2>&1 to redirect it where it can be captured.
I would like to make a script that outputs only the real time value from the time command so I can plot the results. For example time command outputs
real 1m0.001s
user 1m0.000s
sys 0m0.001s
I want to write a script that outputs
60.001
How do I get just real time value from 'time' command in seconds?
If you're using the Bash builtin time, set the TIMEFORMAT variable to %R:
$ TIMEFORMAT=%R
$ time sleep 1
1.022
time can take an optional --format or -f parameter, but you have to use the full path to the time command, /usr/bin/time
/usr/bin/time -f "%e" sleep 3
3.00
Without the path, it'll use the time command of the shell which just treats all arguments as the command, so you'll get an -f: command not found.
If you write \time you enforce not to use the bash built in time.
So with \time -f '%e' command you are done.
Alternatively, use /usr/bin/time or take a look at the similar question
Using time command in bash script.
I tried to redirect the output of the time command, but I couldn't:
$time ls > filename
real 0m0.000s
user 0m0.000s
sys 0m0.000s
In the file I can see the output of the ls command, not that of time.
Please explain, why I couldn't and how to do this.
no need to launch sub shell. Use a code block will do as well.
{ time ls; } 2> out.txt
or
{ time ls > /dev/null 2>&1 ; } 2> out.txt
you can redirect the time output using,
(time ls) &> file
Because you need to take (time ls) as a single command so you can use braces.
The command time sends it's output to STDERR (instead of STDOUT). That's because the command executed with time normally (in this case ls) outputs to STDOUT.
If you want to capture the output of time, then type:
(time ls) 2> filename
That captures only the output of time, but the output of ls goes normal to the console. If you want to capture both in one file, type:
(time ls) &> filename
2> redirects STDERR, &> redirects both.
time is shell builtin and I'm not sure if there is way to redirect it. However you can use
/usr/bin/time instead, which definitely accept any output redirections.
The reason why redirection does not seem to work with time is that it's a bash reserved word (not a builtin!) when used in front of a pipeline. bash(1):
If the time reserved word precedes a pipeline, the elapsed as well as
user and system time consumed by its execution are reported when the
pipeline terminates.
So, to redirect output of time, either use curly braces:
{ time ls; } 2> filename
Or call /usr/bin/time:
/usr/bin/time ls 2> filename
If you don't want to mix output from time and the command.
With GNU time, you can use -o file like:
/usr/bin/time -o tim grep -e k /tmp 1>out 2>err
while tim is output of time, out and err are stdout and stderr from grep.
I use the redirection of stdout and stderr method with braces for testing.
The &>>rpt represents this >>rpt 2>&1 but shorter.
The braces will execute a command(s) in the current shell. See: man bash
{ time ls a*; } &>>rpt
Not the canonical use case, but another way to go.
Longer running simple tasks can be launched in a detached "screen" terminal with logged output. You could even give the log a unique name.
Primarily this method is good for something that will take hours and is invoked over SSH with a need to "check up on" from time to time. In preference to backgrounding and disowning.
screen -dmL time -v ./crackpassword
You get the same output a terminal would get, with the caveat that this is asynchronous. Of course it could be a script. The output may need tweaking.