11

I'm making a backup script for ldap. I want the errors to go to a file in /var/log and the output to go to another file in the backup folder. Currently I'm redirecting to a temp file and then sending the temp file to the log. I'd rather do this as a 1 liner though...

/usr/bin/ldapsearch -x -LLL -b "dc=contoso,dc=com" "(objectclass=*)" -h ldap.server -v 2>>/tmp/ldaptmp.err |
  gzip -c > /mnt/backups/ldap/`date +\%Y\%m\%d`.ldif.gz || 
  logger -t ldapbackup -p local6.err error exit $?

cat /tmp/ldaptmp.err | grep -v "ldap_initialize( ldap://ldap.server )" | 
  grep -v "filter: (objectclass=\*)" |
  grep -v "requesting: All userApplication attributes" >$ERR_LOG
rm -f /tmp/ldaptmp.err

Any ideas on how to redirect stderr and stdout to different pipes to condense this command into 1 line? Or is there a better way?

11

As indicated by this answer at Unix SE:

MyWeirdCommand.sh

#!/bin/bash
echo "1 2   3"
echo "4 5   6" >&2

testRedirection.sh:

#!/bin/bash
(./MyWeirdCommand.sh | cut -f1 >stdout.log) 3>&1 1>&2 2>&3 | cut -f3 >stderr.log

Running yields:

  • stderr.log 6

  • stdout.log 1

| improve this answer | |
  • Slightly simpler for something similar that I was doing: (/tmp/test.sh | gzip > /tmp/out.gz) |& gzip > /tmp/err.gz – Randall Whitman Jul 21 at 21:21
25

In Bash, you can use process substitution to manage the extra file descriptors for you. You may find this a little neater looking than the file descriptor swap method.

command > >(process_stdout) 2> >(process_stderr)

Your command might look something like this:

/usr/bin/ldapsearch -x -LLL -b "dc=contoso,dc=com" "(objectclass=*)" -h ldap.server -v \
  > >( \
    gzip -c > /mnt/backups/ldap/$(date '+%Y%m%d').ldif.gz || 
    logger -t ldapbackup -p local6.err error exit $?
  ) \
  2> >( \
    grep -Ev "ldap_initialize( ldap://ldap.server )|filter: (objectclass=\*)|requesting: All userApplication attributes" > "$err_log" \
  )
| improve this answer | |
  • 1
    This is the correct answer. – Michael Martinez Aug 29 '13 at 18:10
  • You might want to redirect the output back to stderr if you want to keep the chain instead of redirect to a file, something like this: sh f > >(sed -e "s/^/stdout: /") 2> >(sed -e "s/^/stderr: /" >&2 ) – James Moore Sep 27 '17 at 17:03
  • What is the technical name for the >(process) notation? – jchook Jan 13 '19 at 19:04
  • 1
    @jchook I use the term in the first sentence: "process substitution". – Paused until further notice. Jan 13 '19 at 20:30
1

This is how I print stdout and stderr to separate files with timestamps (piping to ts from Debian moreutils package):

(./my_little_script.pl | ts %F\ %T > out.log) 2>&1 | ts > err.log

P.S. if you don't have ts, make your own alias:

alias ts='while IFS= read -r line; do printf "%s %s\n" "$(date +%F\ %T)" "$line"; done'
| improve this answer | |

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.