Search code examples
linuxbashimagemagickimagemagick-convert

How to execute imagemagick with a string as input for filenames - in bash


I am trying to write a code to do the below.

1: Get all the directory names from input line into a string (Number of directory inputs could vary)

2: For all the tiff files in those directories montage the images (using imagemagick) with the same names and save it in the main folder or given folder.

I want to combine two or more images (depending on the number of directories in the command line input). Each directory has image outputs with same name to the other directory. I wanna combine files with the same names from given directories

The code I wrote is below but its not passing $name as variable to montage command. What am I doing wrong here? Any help would be greatly appreciated.

for arg in "$@"; do # 
n1=$arg
fname+=$n1"\${name} " #Get all the directory names in a string with $name at the end. for eg: Baseline/$name
done
echo $fname

for n in $arg/*.tif; do
name="$(basename "$n")"
name1=$(echo "$name" | cut -f 1 -d '.')
montage -tile 3x3 $fname name1.png
exit
done

More DetailsExample


Solution

  • Updated Answer

    Thank you for the clarification, you can do what you want if you save the following as monty.sh and make it executable with:

    chmod +x monty.sh
    

    Here's the code:

    #!/bin/bash
    
    # Goto first subdirectory and take it off args list
    cd "$1"
    shift
    
    # Grab remaining directory names into array
    friends=( "$@" )
    >$2 echo "DEBUG: friends=${friends[@]}" 
    
    # Iterate over files in first directory
    for this in *.tiff ; do
       >&2 echo "DEBUG: this=$this"
       # Generate list of files to montage
       { 
          # ... starting with this one...
          echo "$this"
          # ... and adding in his friends
          for friend in "${friends[@]}" ; do
             next="../${friend}/${this}"
             >&2 echo "DEBUG: next=$next"
             if [ -f "$next" ] ; then
                 echo "$next"
             else
                 >&2 echo "ERROR: file $next is missing"
             fi
          done
        } | magick montage -tile 3x @- ../"${this/tiff/png}"
    done
    

    Then your command will be:

    ./monty.sh Output1 Output2 Output3
    

    or, more succinctly:

    ./monty.sh Output{1,2,3}
    

    In case you are unfamiliar with bash syntax, the code in the middle of the for loop is essentially doing:

    ...
    ...
    { 
       echo first filename to montage onto stdout
       echo second filename to montage onto stdout
       echo third filename to montage onto stdout
    } | magick montage <ALL FILENAMES ON STDIN> result.png
    

    So it is important that all error messages inside {...} are sent to stderr else the error messages will go to the montage command which will interpret them as filenames. That's why all the debug statements start with >&2 echo ... because that directs them to stderr so they don't get mixed up with stdout.


    Original Answer

    I don't understand what you are trying to do, but if you can write all the filenames into ImageMagick's stdin, you can make it montage them like this:

    find . -name "*.tif" -print | magick montage -geometry +0+0 -tile x3 @- result.png