Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BASH: print output on one line

Tags:

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.

like image 919
HTF Avatar asked May 03 '15 17:05

HTF


People also ask

How do I print one line in shell?

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.

How do you echo one line?

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.

How do I print two Echos on the same line?

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.


2 Answers

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.

like image 162
tivn Avatar answered Sep 17 '22 15:09

tivn


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  
like image 30
HTF Avatar answered Sep 21 '22 15:09

HTF