Print all script output to file from within another script - bash

English is not my native language, please accept my apologies for any language issues.
I want to execute a script (bash / sh) through CRON, which will perform various maintenance actions, including backup. This script will execute other scripts, one for each function. And I want the entirety of what is printed to be saved in a separate file for each script executed.
The problem is that each of these other scripts executes commands like "duplicity", "certbot", "maldet", among others. The "ECHO" commands in each script are printed in the file, but the outputs of the "duplicity", "certbot" and "maldet" commands do not!
I want to avoid having to put "| tee --append" or another command on each line. But even doing this on each line, the "subscripts" do not save in the log file. That is, ideally in the parent script, you could specify in which file each script prints.
Does not work:
sudo bash /duplicityscript > /path/log
or
sudo bash /duplicityscript >> /path/log
sudo bash /duplicityscript | sudo tee –append /path/log > /dev/null
or
sudo bash /duplicityscript | sudo tee –append /path/log
Using exec (like this):
exec > >(tee -i /path/log)
sudo bash /duplicityscript
exec > >(tee -i /dev/null)`
Example:
./maincron:
sudo ./duplicityscript > /myduplicity.log
sudo ./maldetscript > /mymaldet.log
sudo ./certbotscript > /mycertbot.log
./duplicityscript:
echo "Exporting Mysql/MariaDB..."
{dump command}
echo "Exporting postgres..."
{dump command}
echo "Start duplicity data backup to server 1..."
{duplicity command}
echo "Start duplicity data backup to server 2..."
{duplicity command}
In the log file, this will print:
Exporting Mysql/MariaDB...
Exporting postgres...
Start duplicity data backup to server 1...
Start duplicity data backup to server 2...
In the example above, the "ECHO" commands in each script will be saved in the log file, but the output of the duplicity and dump commands will be printed on the screen and not on the log file.
I made a googlada, I even saw this topic, but I could not adapt it to my necessities.
There is no problem in that the output is also printed on the screen, as long as it is in its entirety, printed on the file.

try 2>&1 at the end of the line, it should help. Or run the script in sh -x mode to see what is causing the issue.
Hope this helps

Related

How to capture the output of a bash command which prompts for a user's confirmation without blocking the output nor the command

I need to capture the output of a bash command which prompts for a user's confirmation without altering its flow.
I know only 2 ways to capture a command output:
- output=$(command)
- command > file
In both cases, the whole process is blocked without any output.
For instance, without --assume-yes:
output=$(apt purge 2>&1 some_package)
I cannot print the output back because the command is not done yet.
Any suggestion?
Edit 1: The user must be able to answer the prompt.
EDIT 2: I used dash-o's answer to complete a bash script allowing a user to remove/purge all obsolete packages (which have no installation candidate) from any Debian/Ubuntu distribution.
To capture partial output from that is waiting for a prompt, one can use a tail on temporary file, potentiality with 'tee' to keep the output flowing if needed. The downside of this approach is that stderr need to be tied with stdout, making it hard to tell between the two (if this is an issue)
#! /bin/bash
log=/path/to/log-file
echo > $log
(
while ! grep -q -F 'continue?' $log ; do sleep 2 ; done ;
output=$(<$log)
echo do-something "$output"
) &
# Run command with output to terminal
apt purge 2>&1 some_package | tee -a $log
# If output to terminal not needed, replace above command with
apt purge 2>&1 some_package > $log
There is no generic way to tell (from a script) when exactly a program prompts for input. The above code looks for the prompt string ('continue?'), so this will have to be customized per command.

How do I automatically save the output of the last command I've run (every time)?

If I wanted to have the output of the last command stored in a file such as ~/.last_command.txt (overwriting output of previous command), how would I go about doing so in bash so that the output goes to both stdout and that file? I imagine it would involve piping to tee ~/.last_command.txt but I don't know what to pipe to that, and I definitely don't want to add that to every command I run manually.
Also, how could I extend this to save the output of the last n commands?
Under bash this seems to have the desired effect.
bind 'RETURN: "|tee ~/.last_command.txt\n"'
You can add it to your bashrc file to make it permanent.
I should point out it's not perfect. Just hitting the enter key and you get:
matt#devpc:$ |tee ~/.last_command.txt
bash: syntax error near unexpected token `|'
So I think it needs a little more work.
This will break program/feature expecting a TTY, but...
exec 4>&1
PROMPT_COMMAND="exec 1>&4; exec > >(mv ~/.last_command{_tmp,}; tee ~/.last_command_tmp)"
If it is acceptable to record all output, this can be simplified:
exec > >(tee ~/.commands)
Overwrite for 1 command:
script -c ls ~/.last_command.txt
If you want more than 1 command:
$ script ~/.last_command.txt
$ command1
$ command2
$ command3
$ exit
If you want to save during 1 login session, append "script" to .bashrc
When starting a new session (after login, or after opening the terminal), you can start another "nested" shell, and redirect its output:
<...login...>
% bash | tee -a ~/.bash_output
% ls # this is the nested shell
% exit
% cat ~/.bash_output
% exit
Actually, you don't even have to enter a nested shell every time. You can simply replace your shell-command in /etc/passwd from bash to bash | tee -a ~USERNAME/.bash_output.

Issue with scheduling in Linux

I scheduled a script using at scheduler in linux.
The job ran fine but the echo statements which I had redirected to a file are no where to be found.
The at scheduling command is as follows:
at -f /app/data/scripts/func_test.sh >> /app/data/log/log.txt 2>&1 -v 09:50
Can anyone point out what is the issue with the above command.
I cannot see any echo statements from the script in the log.txt file
To include shell syntax like I/O redirection, you'll need to either fold it into your script, or pass the input to at via standard input, like so:
at -v 09:50 <<EOF
sh /app/data/scripts/func_test.sh >> /app/data/log/log.txt 2>&1
EOF
If func_test.sh is already executable, you can omit the sh from the beginning of the command; it's there to ensure that you are passing a valid command line to at.
You can also simply ensure that your script itself redirects all its output to a specific log file. As an example,
#!/bin/bash
echo foo
echo bar
becomes
#!/bin/bash
{
echo foo
echo bar
} >> /app/data/log/log.txt 2>&1
Then you can simply run your script with at using
at -f /app/data/scripts/func_test.sh -v 09:50
with no output redirection, because the script itself already redirects all its output to that file.

Why can't I redirect text to a text file?

I'm writing a bash shell script that has to be run with admin permissions (sudo).
I'm running the following commands
sudo -u $SUDO_USER touch /home/$SUDO_USER/.kde/share/config/kcmfonts > /dev/null
sudo -u $SUDO_USER echo "[General]\ndontChangeAASettings=true\nforceFontDPI=96" >> /home/$SUDO_USER/.kde/share/config/kcmfonts
The first command succeeds and creates the file. However the second command keeps erroring with the following:
cannot create /home/username/.kde/share/config/kcmfonts: Permission denied
I can't understand why this keeps erroring on permissions. I'm running the command as the user who invoked sudo so I should have access to write to this file. The kcmfonts file is created successfully.
Can someone help me out?
Consider doing this:
echo "some text" | sudo -u $SUDO_USER tee -a /home/$SUDO_USER/filename
The tee command can assist you with directing the output to the file. tee's -a option is for append (like >>) without it you'll clobber the file (like >).
You don't need to execute the left side with elevated privs (although it is just echo, this is a good thing to form as a habit), you only need the elevated privs for writing to the file. So with this command you're only elevating permissions for tee.
sudo -u $SUDO_USER echo "some text" >> /home/$SUDO_USER/filename
sudo executes the command echo "some text" as `$SUDO_USER".
But the redirection is done under your account, not under the $SUDO_USER account. Redirection is handled by the shell process, which is yours and is not under the control of sudo.
Try this:
sudo -u $SUDO_USER sh -c 'echo "some text" >> /home/$SUDO_USER/filename'
That way, the sh process will be executed by $SUDO_USER, and that's the process that will handle the redirection (and will write to the output file).
Depending on the complexity of the command, you may need to play some games with escaping quotation marks and other special characters. If that's too complex (which it may well be), you can create a script:
$ cat foo.sh
#!/bin/sh
echo "some text" >> /home/$SUDO_USER/filename
$ sudo -u $SUDO_USER ./foo.sh
Now it's the ./foo.sh command (which executes as /bin/sh ./foo.sh) that will run under the $SUDO_USER account, and it should have permission to write to the output file.

Update shell command history from within bash script

I use control-r on the command line frequently to search for previous commands but cannot get this to work for commands that have just been run in a bash script.
I've tried running the script directly and using 'source' but history shows no record.
Is there anyway to get history updated via a script?
You can try using history -s command to store the command in the history list.
Example:
$ history -s echo foo
[Ctrl+R]
(reverse-i-search)`foo': echo foo
Alternatively, write your commands to a file and then use history -n file to read commands from the file into the current history list.
Example:
$ echo "echo bar" > /tmp/file
$ history -n /tmp/file
[Ctrl+R]
(reverse-i-search)`bar': echo bar

Resources