3

So, here i am, playing with some bash scripts, and there is something that doesn't work:

#!/bin/bash

script -c \
sudo apt-get update &&
sudo apt-get upgrade &&

exit

echo "(Not important for the question)"

I want to run the usual update and upgrade stuff, and also record the output, but when i run the script, it only says that the script started to record in apt-get, shows the usage of sudo ( usage: sudo -h is the first line ), and says that the sript is done. After that it starts the sudo stuff.

What do i need to do in order to record the output of the update&upgrade task? In general, how can i record the output of an entire shell script?

9

If I understand your question correctly, you can use the following:

#!/bin/bash

apt-get update &> update.log
apt-get -y upgrade &> upgrade.log

echo "all done"

Save this script as run_updates.sh, make it executable with chmod 755 run_updates.sh and run it with sudo ./run_updates.sh.
If you want to save all output in one file, remove the &> updates.log and &> upgrades.log from the script and run the script as sudo./run_updates.sh &> run_updates.log


Explanation of the script:

  • apt-get update &> update.log runs apt-get update and saves the output in update.log
  • apt-get -y upgrade &> upgrade.log runs apt-get upgrade and saves the output in upgrade.log. The -y prevents apt from asking to continue (it assumes "yes")

A note on redirections:
You can use the redirections below to "send" output from a command or script to a file.

  • &> redirects STDOUT and STDERR
  • > or 1> redirects STDOUT
  • 2> redirects STDERR

A note on sudo:
This is probably the reason why you got errors. When running a command that needs sudo in a script, it is a good idea to put the command without sudo in the script and run the script with sudo. Otherwise, you would have to give your sudo password to the script in some way, which is bad.


Edit:
In the following code, the output of both apt commands is redirected to update.log. The double > (>>) is used to append data to a file (instead of replacing it)

#!/bin/bash

apt-get update &> update.log
apt-get -y upgrade &>> update.log

echo "all done"
  • I didn't realize i could run the script itself as sudo. It'll make my life easier, thanks. About the redirection, is it possible to write something in the script to automatically record the output of both commands into the same file instead of writing the output on separate files? – macacomen98 Feb 14 '16 at 20:10
  • @macacomen98 see my edit ;-) – Wayne_Yux Feb 14 '16 at 22:50
4

In general, to log the output of the entire script, redirect the output of the entire script:

exec &> some.log
# Or, when using `/bin/sh`:
# exec >some.log 2>&1

The exec builtin is often used to change the open file descriptors or add new file descriptors (the sources and destinations of input and output) for the shell.

For example, given example.sh:

#! /bin/bash
exec &> some.log
ls foo
echo foo

On running:

$ ./example.sh
$ cat some.log
ls: foo: No such file or directory
foo

If you want both output to screen and to a file, use tee with process substitution:

exec &> >(tee some.log)
3

No need for a script, just do it in one line using Bash redirections and tee:

{ sudo apt-get update && sudo apt-get upgrade ; } |& tee output.txt

In case you want to append the output to an existing logfile, add the -a option after tee.


To explain what it does:

  • { ... ; } groups the ... commands inside, so that the output redirections we will perform apply to all commands and not just the last one. Please pay attention on the space after { and before } as well as on the semicolon ; after all commands! (thanks @kos for telling me to avoid spawning a subshell)
  • sudo apt-get update && sudo apt-get upgrade are the example commands we want to run and record here. You may exchange this whole part with whatever you like.
  • |& (the "pipe") redirects both output streams (STDERR/standard error and STDOUT/standard output) of the command left of it to the STDIN (standard input) of the command on the right. (thanks @muru for teaching me about the & to redirect both STDOUT and STDERR)
  • tee output.txt copies everything it reads from STDIN to STDOUT and also saves it to output.txt. If the target file already exists, it will get overwritten silently. You can append to the file instead if you use tee -a output.txt.
  • About the script, i usually do this on the terminal. I use the script just for a little bit of fun and to learn some stuff. But thanks for the note on the redirections STERR and STDOUT to the same file, didn´t know i could do that. – macacomen98 Feb 14 '16 at 20:01
  • Since you're there, you could also drop tee: (sudo apt-get update && sudo apt-get upgrade) >output.txt 2>&1. And if you want to go even further, you could also avoid to spawn the subshell: { sudo apt-get update && sudo apt-get upgrade; } >output.txt 2>&1 ;) – kos Feb 14 '16 at 23:08
  • 2
    Bash has |& for 2>&1 |. – muru Feb 14 '16 at 23:21
  • @kos I keep the tee, because usually the people still want to see what the command does. But the curly braces seem like an improvement. – Byte Commander Feb 15 '16 at 7:22
  • 1
    @macacomen98 ./file.txt or bash file.txt – muru Feb 15 '16 at 18:14

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.