1

I have shell script with some function. I am trying to capture the successful execution of each command to one file and stderr/echo statements with error message to be copied to another file. But the error statements is not redirecting to error file instead it is redirecting to actual log file. Below is my code for reference.

Bash script 
***********
#! /bin/sh
Function_1()
{
now=$( date '+%Y%m%d%H%M' )
eval logfile="$1"_"$now".log
exec 2>&1 1>>$logfile     
echo " "
echo "############################"
echo "Function execution Begins"
echo "############################"
echo "Log file got created with file name as $1.log"
eval number=$1
eval  path=$2
echo "number= $number"
ls -lR $path >> temp.txt
    if [ $? -eq 0 ]; then
    echo " Above query executed."
    else
    echo "Query execution failed"
    fi
    echo "############################"
    echo "Function execution Ends"
    echo "############################"
    echo " "
}
5
  • Did you write this code? What is your actual question (what happens instead?) – Jeff Schaller Nov 6 '19 at 13:12
  • Do you think i copied it from somewhere ?? I need only the error statement & stderr to be copied to error file and other logs to redirect to actual log file. – user78873 Nov 6 '19 at 13:31
  • 3
    Then why did you do exec 2>&1 1>>$logfile, which redirects both? – muru Nov 6 '19 at 13:42
  • yes thats correct, i tried all the possibilities. This code is what i have in my older version of the script – user78873 Nov 6 '19 at 13:50
  • unix.stackexchange.com/questions/84279/… has info on more complex redirs. In my answer I show why 2>&1 first does nothing. (in second place, yes) (about "Duplication" of FDs) – user373503 Nov 6 '19 at 15:36
2
exec 2>&1 1>>$logfile 

This will first redirect stderr to where ever stdout goes at that point, and only then redirect stdout to the logfile. The result is likely to be that stderr goes to the terminal, and stdout goes to the logfile.

(I'm not sure how you meant that to produce output into two files, as there's really only one mentioned. Unless the idea is to run the script as script.sh > errorfile, but that would seem odd.)

Of course, all your echo commands just print to stdout, so their output will all go to the same place. ls might produce errors though, they'd go the terminal then.

If you want to redirect the normal and error outputs to two different files, just do that:

exec 1>>"$logfile" 2>>"$errorfile"

Now you can use:

echo "Something worked normally"

and

echo "This is an error message" >&2

to output normal status output to the log, and errors to the error file. (Note the redirection.)


As another thing:

eval logfile="$1"_"$now".log
eval number=$1
eval path=$2

The evals here are useless, and will break things, e.g. if $1 contains whitespace, or worse a command substitution. So, just get rid of them. An assignment in the shell is just var=value, so:

logfile="$1"_"$now".log
number=$1
path=$2

That first one can also be written as just logfile=$1_$now.log but it's up to you to decide which is prettier.

2
  • There's actually no need to use curly braces in ${1}_$now.log as variables can't begin with digits. $1_$now.log does the right thing. If you need to access positional parameters beyond $9 you do need to use the curly braces. – Kusalananda Nov 6 '19 at 18:22
  • @Kusalananda, ahh yes of course. It's only cases like ${foo}_$bar that need them. – ilkkachu Nov 6 '19 at 18:32
1

echo "Query execution failed"

This is only semantically a error message.

exec 2>&1 1>>$logfile

This can make sense -- the first part does nothing, I tested that for bobdylan lately -- but where is that error file you mention?


I understand the comments: this script is not so nice to interpret.


Here a few basic examples. User bobdylan I cannot find anymore.

]# ls . NOsuch         
ls: cannot access 'NOsuch': No such file or directory
.:
foo

Both STDOUT 1 and STDERR 2 go to the standard output device, "the terminal".

Now I separate the two. Instead of /dev/null you can put any filename.

]# ls . NOsuch >/dev/null
ls: cannot access 'NOsuch': No such file or directory

]# ls . NOsuch 2>/dev/null
.:
foo
]# ls . NOsuch >/dev/null 2>&1
(EMPTY)

]# ls . NOsuch 2>&1 >/dev/null     
ls: cannot access 'NOsuch': No such file or directory

(2>&1 has no effect)  

And

ls ... >ls.out 2>ls.ERRORS

...should produce no output, but save both "streams" separately.


Leave the script plain, and make the difference when you call it.

2
  • 1
    i want that error message only to redirect to an error file. If i use exec 2>&1 1>>$logfile both output and error is getting redirected to single file. But i want to separate the error message in one file and other log in one file. Hope this clarifies – user78873 Nov 6 '19 at 14:58
  • No it does not really clarify: "the error message": how you define? is it this "failed" line? Then just write that line to /tmp/ERROR. Do you mean "all errors"? That would be exec 2>$errorfile. But exec 2>&1 ... just redirects STDERR to where STDOUT is going now, and that is STDOUT. But that is only a detail even. – user373503 Nov 6 '19 at 15:29
0

As was stated previously, you are redirecting both STDERR and STDOUT to the same file. ... exec 2>&1 1>>$logfile

This line is redirecting STDERR to STDOUT, then redirecting the STDOUT ( which is also STDERR ) to the file descriptor $logfile. Redirection and file descriptors can get confusing. But, check this out for some helpful information:

https://likegeeks.com/shell-scripting-awesome-guide-part4/

Also, google searches on linux redirection and linux file descriptors could be beneficial.

cheers,

JB

3
  • No, they don't go to the same file. exec 2>&1 1>>$logfile first makes stderr point to where ever stdout goes at that point, and then makes stdout go to the logfile. (Try it, see what e.g. ( exec 2>&1 1>>logfile; echo stdout; ls /nosuchfile ) outputs to the terminal and to logfile) – ilkkachu Nov 6 '19 at 18:02
  • Of course, file descriptors are contextual.. That script is running in a different context. The STDOUT and STDERR descriptors of the TTY are not the same as the STDOUT and STDERR of the script. – Headless Bunny Nov 6 '19 at 18:21
  • err, yes, they're contextual in the sense that each process has its own set of fd's, and yes, the script does run in a different process than the shell it was launched from. But that exec command still doesn't redirect both stdout and stderr to the same file. – ilkkachu Nov 6 '19 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.