Thursday, February 3, 2011

Bash sequential commands. Calling functions without launching new threads.

Hello ,

I have the following script (at the end of the explanation and question).

There is two functions. On the first function there is a call to firefox -print extension. Everything works fine if I run it line by line.

The problem is that inside a bash script firefox is called many times in a few seconds instead of being called once at a time and waiting to finish.

I donnot would like to add a sleep in the funcion because I don't know how long can it take.

There is any way to force bash to do not launch threads? (which I suppose is doing)

Thanks.

This is my script .(it's bash and not sh because of the command let)

#!/bin/bash

####TODO###
####variables
# join files
# send with attachment

## Date, to be used as reference on tmp files
DATE=`date +%Y%m%d`
## File where all webs to report are listed
WEBSFILE="/home/marc.riera/Desktop/reports/websfile.txt"
## Where to store all the files. 
WORKDIR="/home/marc.riera/Desktop/reports"

##################do not edit under this line
TMPDIR=$WORKDIR/$DATE
test -d $TMPDIR || mkdir -p $TMPDIR && echo "Create folder $TMPDIR for temporal usage"
REPORT=$WORKDIR/Report_$DATE.pdf

##firefox -print "http://fbmsgga01/ganglia/?m=cpu_report&r=month&s=descending&c=CPU+cluster&h=&sh=1&hc=4&z=small" -printmode pdf -printdelay 5 -printfile ~/Desktop/reports/test.pdf
firefoxprint (){
     web2Print=$1
     outputFile=$2
     echo -n "printing $1 on $2"
     firefox -print "$web2Print" -printmode pdf -printdelay 5 -printfile $outputFile
}

##gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=dospdf.pdf -dBATCH ganglia.pdf test.pdf
pdfjoin (){
     outputFile=$1
     origA=$2
     origB=$3
     echo -n "Joining $origA and $origB into $outputFile"
     gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=$outputFile -dBATCH $origA $origB
}


###################################### MAIN
#######################################
clear
COUNTER=0
for web in `cat $WEBSFILE|grep -v '^#'`
do
     firefoxprint $web $TMPDIR/$COUNTER.pdf
     let COUNTER+=1
done
echo "--------------------" $COUNTER
while [ $COUNTER -gt 0 ]; do
    let COUNTER=COUNTER-1
    pdfjoin $REPORT $REPORT $TMPDIR/$COUNTER.pdf
done

echo "done"
exit 0
  • I'm not terribly familiar with using FireFox to print, but have you played around with bash's wait command? You can feed it the specific PID to wait for. So by following one of your firefox print commands, you could just do wait $!. Or, if you don't specify any and just use wait, it will simply wait for all child processes to finish.

    I can't guarantee that FireFox will play nicely with this. But it's worth a shot.

    marc.riera : Nice try, but still opens as many firefox as lines in the file. And don't wait for the print command to finish. I guess firefox does not play nice with this.
    Gilles : @Christopher: the `wait` builtin can only wait for the shell's own background processes (started with `&`). marc.riera's script contains no background process, so `wait` is no use.
  • At the end of your firefoxprint() routine add:

      while [ ! -s $outputFile ]; do
        sleep 1
      done
    

    which should get you at least some delay - it waits until there's a non-zero-length output file before continuing. Hopefully this will slow it down enough that subsequent calls will use the existing firefox and not think they have to spawn their own.

    From pjz
  • When you call firefox without specifying a full directory, it will run a wrapper script which does an exec of the actual executable. This may be causing your problem or the executable may be doing a double fork which causes it to run in the background without using &. I don't know how you can prevent this.

    Gilles : @Dennis: actually, the presence of `exec` means that there is no double fork.
  • If there is a running firefox, the call to firefox just contacts it, transmits the print request and exits immediately. The print request is executed asynchronously in the running instance. I don't know if there is a way to get a notification when the printing is finished.

    A workaround (untested) would be to create a fresh profile in your script (unpack a prepared zip under a random name). You can run multiple instances of firefox as long as they use different profiles. Erase the temporary profile once firefox exits. This assumes that the printing extension doesn't leave the firefox instance running; if it does, you could hack it to exit firefox once it's finished.

    From Gilles
  • There is only one wait to make it.

    a) Create a dedicated profile at firefox for printing:

    firefox -no-remote -ProfileManager

    b) Start firefox by firefox -no-remote -P

    c) do wait

    From Dmitry
  • Ok, finally solved. Thanks for all your help.

    There was another issue: the cron launches the firefox without env variables, so I had to define the display where to work.

    Here is the final code.

    #!/bin/bash
    
    #autor : Joan Marc Riera Duocastella. 
    #license : BSD i guess. I just don't care. :)
    # firefox -print option depends on http://sites.google.com/site/torisugari/commandlineprint2  
    # it's kind of possible that a file inside de .xpi extension must be edited to get bigger pdf . Depends on the html you would like to print. Good html code does not need it. 
    
    
    ####variables
    
    ## Date, to be used as reference on tmp files
    DATE=`date +%Y%m%d`
    ## File where all webs to report are listed
    WEBSFILE="/home/marc.riera/Desktop/reports/websfile.txt"    # urls to print. lines starting with # will be ignored.
    ## Where to store all the files. 
    WORKDIR="/home/marc.riera/Desktop/reports"
    MAILTO="marc.riera@barcelonamedia.org"   # other mails can be added just with a single space between
    MAILTEXTFILE=$WEBSFILE         
    FFPROFILE="cnm-profile"  #FIREFOX PROFILE - create it with firefox -ProfileManager while no other firefox instances running
    
    ##################do not edit under this line
    #echo "$DATE - $0"
    logger $0
    TMPDIR=$WORKDIR/$DATE
    test -d $TMPDIR && rm -f $TMPDIR/*.pdf|| mkdir -p $TMPDIR && echo "Create folder $TMPDIR for temporal usage"
    REPORT=$WORKDIR/Report_$DATE.pdf
    
    ##firefox -print "http://fbmsgga01/ganglia/?m=cpu_report&r=month&s=descending&c=CPU+cluster&h=&sh=1&hc=4&z=small" -printmode pdf -printdelay 5 -printfile ~/Desktop/reports/test.pdf
    firefoxprint (){
        web2Print=$1
        outputFile=$2
        #echo "printing $1 on $2"
        env DISPLAY=:0.0 firefox -P $FFPROFILE -no-remote -print "$web2Print" -printmode pdf -printdelay 15 -printfile $outputFile &
        while [ ! -s $outputFile ]; do
              sleep 1
        done
    }
    
    ##gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=dospdf.pdf -dBATCH ganglia.pdf test.pdf
    pdfjoin (){
        outputFile=$1
        tempdir=$2
        cd $tempdir
        gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=$outputFile -dBATCH `ls -tr $tmpdir`
        wait
    }
    
    sendmail (){
        #echo "Sending mail"
        mutt -s "Report del dia $DATE" -a $REPORT -- $MAILTO < $MAILTEXTFILE
        wait
    }
    
    ###################################### MAIN
    #######################################
    COUNTER=0
    for web in `cat $WEBSFILE|grep -v '^#'|grep -v '^$'`
    do
        firefoxprint $web $TMPDIR/$COUNTER.pdf
        let COUNTER+=1
    done
    pdfjoin $REPORT $TMPDIR
    sendmail
    exit 0
    

    I'm still up for improvements, but by now it does what I need.

    From marc.riera

0 comments:

Post a Comment