I've got this simple script below to stream compressed MySQL dumps to Amazon S3 bucket in parallel:
#!/bin/bash
COMMIT_COUNT=0
COMMIT_LIMIT=2
for i in $(cat list.txt); do
echo "$i "
mysqldump -B $i | bzip2 -zc | gof3r put -b s3bucket -k $i.sql.bz2 &
(( COMMIT_COUNT++ ))
if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]; then
COMMIT_COUNT=0
wait
fi
done
if [ ${COMMIT_COUNT} -gt 0 ]; then
wait
fi
The output looks like this:
database1
database2
duration: 2.311823213s
duration: 2.317370326s
Is there a way to print this on one line for each dump?
database1 - duration: 2.311823213s
database2 - duration: 2.317370326s
The echo -n
switch doesn't help in this case.
EDIT: Wed May 6 15:17:29 BST 2015
I was able to achieve expected results based on accepted answer:
echo "$i -" $(mysqldump -B $i| bzip2 -zc | gof3r put -b s3bucket -k $i.sql.bz2 2>&1) &
- however a command that is running in a subshell is not returning exit status to a parent shell because it's running in parallel so I'm not able to verify if it succeed or failed.
There are a couple of different ways we can print a newline character. The most common way is to use the echo command. However, the printf command also works fine. Using the backslash character for newline “\n” is the conventional way.
Use the echo command, used with the append redirection operator, to add a single line of text to a file. This adds the message Remember to back up mail files by end of week. to the end of the file notes.
The 2 options are -n and -e . -n will not output the trailing newline. So that saves me from going to a new line each time I echo something. -e will allow me to interpret backslash escape symbols.
I think this command will do what you want:
echo "$i -" `(mysqldump -B $i | bzip2 -zc | gof3r put -b s3bucket -k $i.sql.bz2) 2>&1` &
Or, use $()
in place of backticks :
echo "$i -" $( (mysqldump -B $i| bzip2 -zc | gof3r put -b s3bucket -k $i.sql.bz2) 2>&1 ) &
The echo
command will wait for mysqldump ..
result to finish before try to print together with $i
. The sub-shell ( … )
and error redirection 2>&1
ensure that error messages go into the echoed output too. The space after the $(
is necessary because $((
without a space is a different special operation — an arithmetic expansion.
Thanks for all your help but I think I've finally found an optimal solution for this.
Basically I used xargs
to format the output so each entry (dump name + duration time) is on one line. I also added the job spec to wait
command to get the exit status:
man bash
wait [n ...] Wait for each specified process and return its termination status. Each n may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If n is not given, all currently active child processes are waited for, and the return status is zero. If n specifies a non-existent process or job, the return status is 127. Otherwise, the return status is the exit status of the last process or job waited for.
Test:
# sh -c 'sleep 5; exit 1' &
[1] 29970
# wait; echo $?
0
# sh -c 'sleep 5; exit 1' &
[1] 29972
# wait $(jobs -p); echo $?
1
Final script:
#!/bin/bash
COMMIT_COUNT=0
COMMIT_LIMIT=2
while read -r i; do
mysqldump -B $i | bzip2 -zc | gof3r put -b s3bucket -k $i.sql.bz2 |& xargs -I{} echo "${DB} - {}" &
(( COMMIT_COUNT++ ))
if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]; then
COMMIT_COUNT=0
wait $(jobs -p)
fi
done < list.txt
if [ ${COMMIT_COUNT} -gt 0 ]; then
wait $(jobs -p)
fi
if [ $? -ne 0 ]; then
echo "ERROR: Backups failed"
exit 1
fi
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With