linux將其列印訊息重新導向並儲存檔案---Bash Redirections Using Exec

來源:互聯網
上載者:User
Jun 11, 2010  By Mitch Frazier in

  • HOW-TOs

If you've used the command line much at all you know about I/O redirectionfor redirecting input to and/or output from a program.What you don't see all that often or that you may not be familiarwith is redirecting I/O inside a bash script.And I'm not talking
about redirections that you use whenyour script executes another command, I'm talking about redirectingyour script's I/O once it has already started executing.

As an example, let's say that you want to add a --log optionto your script and if the user specifies it you want all the outputto go to a log file rather than to the stdout.Of course, the user could
simply redirect the output on the command line,but let's assume there's a reason why that option doesn't appeal to you.So, to provide this feature in your script you can do:

#!/bin/bashecho hello# Parse command line options.# Execute the following if --log is seen.if test -t 1; then    # Stdout is a terminal.    exec >logelse    # Stdout is not a terminal, no logging.    falsefiecho goodbyeecho error >&2

The if statement uses test to see if file descriptor number one isconnected to a terminal (1 being the stdout).If it is then the exec command re-opens it for writing on thefile named
log. The exec command without a command but withredirections executes in the context of the current shell,it's the means by which you can open and close files and duplicate file descriptors.If file
descriptor number one is not on a terminal then we don't change anything.

If you run this command you'll see the first echo and the lastecho are output to the terminal.The first one happens before the redirection and the secondone is specifically redirected to stderr (2 being stderr).So, how do you get stderr into the log file
also?Just one simple change is required to the exec statement:

#!/bin/bashecho helloif test -t 1; then    # Stdout is a terminal.    exec >log 2>&1else    # Stdout is not a terminal, no logging.    falsefiecho goodbyeecho error >&2

Here the exec statement re-opens stdout on the log file and thenre-opens stderr on the same thing that stdout is opened on(this is how you duplicate file descriptors, aka dup them).Note that order is important here: if you change the orderand re-open stderr
first (i.e. exec
2>&1 >log),then it will still be on the terminal since you'reopening it on the same thing stdout is on and at this point it'sstill the terminal.

Perhaps mainly as an exercise, let's try to do the same thingeven if the output is not to the terminal.We can't do what we did above since re-opening stdout on thelog file, when it's currently connected to a file redirectionor to a pipeline, would break
the redirection/pipeline that the userspecified when the command was invoked.

Given the following command as an example:

bash test.sh | grep good

What we want to do is manipulate things so that it appears thatthe following command was executed instead:

bash test.sh | tee log | grep good

Your first thought might be that you could change the exec statementto something like this:

exec | tee log &       # Won't work

and tell exec to re-open stdout on a background pipeline into
tee,but that won't work (although bash doesn't complain about it).This just pipes exec's output to tee,and since exec doesn't produce any output in this instance,tee simply creates an empty file and exits.

You might also think that you can try some dup-ing of file descriptors andstart tee in the background with it taking input from and writing output todifferent file descriptors.And you can do that, but the problem is that there's no way to create anew process
that has its standard input connected to a pipe so that wecan insert it into the pipeline (although see the postscript at the end of this article).If we could do this, the standard output of the tee command would be easy sinceby default that goes to the same
place the main script's output goes to, so wecould just close the main script's output and connected it to our pipe(if we just had a way to create it).

So are we at a dead end? Ahhhh no, that would be a different operating systemyou're thinking of.The solution is actually described in the last sentence of theprevious paragraph. We just need a way to create a pipe, right?Well let's use named pipes.

#!/bin/bashecho helloif test -t 1; then    # Stdout is a terminal.    exec >logelse    # Stdout is not a terminal.    npipe=/tmp/$$.tmp    trap "rm -f $npipe" EXIT    mknod $npipe p    tee <$npipe log &    exec 1>&-    exec 1>$npipefiecho goodbye

Here, if the script's stdout is not connected to the terminal,we create a named pipe (a pipe that exists in the file-system) using mknodand setup a trap to delete it on exit.Then we start tee in the background reading from the named pipe and writing to the
log file.Remember that tee is also writing anything that it reads on its stdinto its stdout.Also remember that tee's stdout is also the same as the script's stdout(our main script, the one that invokes tee) so the output from tee's stdoutis going to go wherever
our stdout is currently going(i.e. to the user's redirection or pipeline that was specified on the command line).So at this point we have tee's output going where it needs to go:into the redirection/pipeline specified by the user.

Now all we need is to get tee reading the right data.And since tee is reading from a named pipe all we need to dois redirect our stdout to the named pipe.We close our current stdout (with
exec 1>&-) andre-open it on the named pipe (with
ezec 1>$npipe).Note that since tee is also writing to the redirection/pipeline that wasspecified on the command line, our closing the connection does notbreak anything.

Now if you run the command and pipe it's output to grep as aboveyou'll see the output in the termimal and it will also be saved in the log file.

Many such journeys are possible, let the man page be your guide!

p.s. There's another way to do this using Bash 4's coproc statement, butthat'll wait for another time.

本文轉自:http://www.linuxjournal.com/content/bash-redirections-using-exec

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.