Search code examples
bashlistgdal

BASH: using gdal_warp to merge tifs using a list


I want to merge all mosaics in a database I have which includes several directories. I have attempted to do this, but my final mosaic 'mergedM.tif' is just a mosaic of the last item in my list (mosaic_list). How do I get gdal_warp to merge all the items in my list?

This is my BASH script, for some reason the final mosaic 'mergedM.tif' is only showing the last item in my mosaic_list.

basepath=/home/rose/Desktop/b #change this as top level directory

cd $basepath
dir_list=$(ls -d -1 $PWD/**) #create list of directories 

for i in $dir_list
do
    x=$(basename $i)
    mosaic_list=$basepath/$x/$x.tif #create list of tifs including text file 
    echo $mosaic_list >> mosaiclist.txt

done

gdalwarp -of GTiff -s_srs EPSG:2193 -t_srs EPSG:2193 -dstnodata -9999 $mosaic_list mergedM.tif #creates mosaic of selected files(should do)

The echo for my $mosaic_list was this;

/home/rose/Desktop/b/0900Rich/0900Rich.tif
/home/rose/Desktop/b/0900Takaka/0900Takaka.tif
/home/rose/Desktop/b/1000StArn/1000StArn.tif
/home/rose/Desktop/b/1000TakaHWS/1000TakaHWS.tif
/home/rose/Desktop/b/1100AorereVPost/1100AorereVPost.tif

Solution

  • You don't need a loop. You can use your glob directly:

    gdalwarp -of GTiff -s_srs EPSG:2193 -t_srs EPSG:2193 -dstnodata -9999 "$basepath"/**.tif /tmp/mergedM.tif
    

    Notice that I put the output in /tmp/mergedM.tif instead of "$basepath"/mergedM.tif. This is just in case you will run the command a second time, to avoid mergedM.tif from getting included in the list by mistake.

    What was wrong with your script

    The loop iterates over the list of files. In each iteration, the variable mosaic_list takes on the value of the current file. You append it to the file mosaiclist.txt. This file should have all the files. So far so good.

    Then after the loop, you run gdalwarp ... $mosaic_list mergedM.tif. What is the value of the mosaic_list variable at this point? It's the last item in the list. The complete list is in a file. Perhaps you thought they were somehow accumulating in this variable. That's not how loops work.

    So that's why the script didn't do what you expected.

    There were other problems too, in terms of Bash scripting. You should never parse the output of ls. It's fragile, many things can go wrong. To have a robust solution, either use glob patterns, or the find ... -exec command.

    Also be careful of quoting. Variables used in command arguments should be enclosed in "..." to protect from word splitting and globbing. (See how I did at the top of this post.)