I need to use a function that has as input multiple files. These files are related by the filename (e.g. dog1_animal.txt, dog2_animal.txt, dog3_animal.txt, cat1_animal.txt, cat2_animal.txt, cat3_animal.txt, and so on...) My idea is to check for those file that are named with a similar patter, but the point is that I don't want to write the pattern but the code should recognise, among these files, which one has a similar name and send them to the function. I have three files for each category; I thought that a nested loop could work, actually it's not like that

for file in *.txt; 
do for file2 in *.txt; 
do for file3 in *.txt;
do if [[ "${file3%_*}" == "${file2%_*}" ]] && [[ "${file3%_*}" == "${file2%_*}" ]] && [[ $file1 != $file3 ]] && [[ $file3 != $file1 ]] && [[ $file3 != $file1 ]]; 
echo "${file%_*}${file2%_*}${file3%_*}"; ##my supposed comand that 
uses file file2 file 3

the problem is that it should iterate through all files, find those have similar name, use them in the function, a again, untile all the files are processed.

  • Sorry but i've posted the wrong code, there are obv some errors, but still not work. I want to use them in a tool that use $file, $file2 and $file3. this tools takes as input three files. let's say that I want to echo them
    – wildos
    Apr 24 at 20:18
  • In that case, please edit your post to correct inaccuracies and errors. Don't use the comment section - comments are difficult to read, lack the formatting options of the question body, and are subject to removal by moderators without notice.
    – AdminBee
    Apr 28 at 14:53

1 Answer 1


Assuming you know that you will always want to use the files in groups of three, that the pattern *.txt matches all relevant files (and no more), and that the files are correctly sorted (as the ones that you mention in the question would be).

Assuming furthermore that you want to call some utility called some_utility with sets of three files at a time, then you may do so with xargs:

printf '%s\0' *.txt | xargs -0 -n 3 some_utility

This would generate a nul-delimited list of filenames using printf. This list would be sent to xargs, and it would pick out three names at a time and call some_utility with these as arguments. When the utility has terminated, it would do the same with the next three filenames, etc.

Testing (with echo):

$ touch {dog,cat,mouse,horse}{1..3}_animal.txt     
$ touch {tree,flower}{1..3}_plant.txt
$ printf '%s\0' *.txt | xargs -0 -n 3 echo
cat1_animal.txt cat2_animal.txt cat3_animal.txt
dog1_animal.txt dog2_animal.txt dog3_animal.txt
flower1_plant.txt flower2_plant.txt flower3_plant.txt
horse1_animal.txt horse2_animal.txt horse3_animal.txt
mouse1_animal.txt mouse2_animal.txt mouse3_animal.txt
tree1_plant.txt tree2_plant.txt tree3_plant.txt

A slightly more complicated example using the same files as above:

$ printf '%s\0' *.txt | xargs -0 -n 3 bash -c 'printf "%s %s %s\n" "${@%_*}"' bash
cat1 cat2 cat3
dog1 dog2 dog3
flower1 flower2 flower3
horse1 horse2 horse3
mouse1 mouse2 mouse3
tree1 tree2 tree3
  • thank you very much, that's what I was looking for. I started coding few days ago and still don't know exactly how bash works. The tool is called freebayes and could take as inpunt -n .bam files. I have a folder with many bam files, but they are all named with an identification number. So i was trying to match all those have the same id and use them in freebayes
    – wildos
    Apr 24 at 20:29
  • 1
    @wildos For the future, always give information like that up front and use real filenames if at all possible. You will notice that answers may become more relevant if you don't try to "dumb down" the question. For example, I assumed that you always have groups of three files. Is that still the case?
    – Kusalananda
    Apr 24 at 20:33
  • my bad, you are completely right! I thought that being too much detailed I would have get a too specific answer, while I wanted to be more vague with an easier example to understand generally the syntax.
    – wildos
    Apr 24 at 20:36
  • actually the script works but ther's a problem with the output. freebays should save a file for each three bam file but in this way create a unique big file. printf '%s\0' *.bam | xargs -0 -n 3 freebayes -f all.fasta -m 20 -C 5 -Q 10 --min-coverage 10 > file.vcf
    – wildos
    Apr 24 at 20:59
  • @wildos No, that won't work, but you will be able to use something like ... | xargs -0 -n 3 sh -c 'freebayes -f all.fasta -m 20 -C 5 -Q10 --min-coverage 10 "$@" >"${1%_*}.vcf"' sh. Don't forget that trailing sh.
    – Kusalananda
    Apr 24 at 21:22

Not the answer you're looking for? Browse other questions tagged or ask your own question.