1

I am trying to direct user input file into while loop, but kept on failing when ran the script.

The user input file genelist contained a list of numbers where I have been using as prefixes of my other files. Eg. 012.laln, 012.model.

genelist:

012
013
025
039
109
.
.
.

This is the script I have been testing on.

#!/usr/bin/env bash
read -pr "genefile: " genelist
read -pr "treefile: " trees
read -pr "workers: " workers

while read -r i; do
    while read -r j; do
        raxml-ng --sitelh --msa "$i".laln --model "$j".model --tree "${trees}" --workers "${workers}" --prefix "$i"-rT;
    done < "$genelist".model; 
done < "$genelist"

In order to execute raxml-ng tool, I need to input files for --msa, --model, --tree, --workers and --prefix for output file name. I need to repeat the process with multiple files, each 012.laln need to match with 012.model and generate output file named 012-rT. The input files for tree and workers are the same for all the files.

I kept on getting error:

line 2: read: `genefile: ': not a valid identifier
line 3: read: `treefile: ': not a valid identifier
line 4: read: `workers: ': not a valid identifier

Modifying the way I call the user input file "genelist" in a few ways but with no avail.

while read -r "${genelist}" ... 
while read -r "${genelist{@}}" ...
while read -r "{genelist}" ...

Before this, I have been using for loops, i.e., the one-liner below. It worked well. I would like to try on while loops if possible.

for i in $(cat genelist); do for j in $(cat $i.model); do raxml-ng --sitelh --msa $i.laln.trgc38_1l --model $j --tree trees --workers 4 --prefix $i-rT; done; done

Questions: What is the correct and neat way to call the user input file genelist into the while loops?

There are some example I found in here but those are using numbers/number sequences in the loops. The answers suggested using C in for/while loops to solve the issue. But that doesn't seemed to be relevant for my case.

Meanwhile, any better alternative for for/while loops in this case is also welcome!

1
  • 1
    Looking at the kind of thing you're doing, I think you might also be interested in our sister site, Bioinformatics. Please note that there is absolutely nothing wrong with this question, it is entirely on topic and welcome here. I just thought you might find the other site useful in future since often, although not in this case, bioinformatics issues can require some field knowledge (e.g. how the standard formats work etc.).
    – terdon
    Nov 16, 2021 at 16:12

1 Answer 1

2

The errors have nothing to do with your loop. You are using read wrong:

$ read -pr "genefile: " genelist
bash: read: `genefile: ': not a valid identifier

The -p option needs an argument, and you're giving it r as the argument if you use -pr. You need:

read -p "genefile: " genelist

or

read -rp "genefile: " genelist

Also, a general albeit personal, note. Don't use read! That just makes the user's life harder for no benefit: it means I can't copy/paste the command into my readme file to redo it since the input is not part of the command. It means I can trivially make a typo since you are asking me to laboriously type out things instead of using tab-completion. It also means this is very hard to automate. Nine times out of ten, it is better to pass everything as an argument when launching instead of blocking execution to request input:

#!/usr/bin/env bash

genelist=$1
trees=$2
workers=$3

while read -r i; do
    while read -r j; do
        raxml-ng --sitelh --msa "$i".laln --model "$j".model --tree "${trees}" --workers "${workers}" --prefix "$i"-rT;
    done < "$i".model; 
done < "$genelist"

You can then launch the script with:

script.sh "$genelist" "$trees" "$workers"
5
  • One optimization here would be to read $genelist.model or $genelist (whichever is smallest) into an array with mapfile and loop over that array in the inner loop.
    – Kusalananda
    Nov 16, 2021 at 18:51
  • @terdon I might be too frustrated in troubleshooting the script that the error line only made sense when you pointed it out! XD Had everything sorted out except for the part I posted here. The script worked well now! Also, will discard read command to input the required files. That was a great advice. THANKS!
    – web
    Nov 17, 2021 at 3:58
  • Btw, I realized that the input file name for the inner loops should be "$i".model instead of "$genelist".model, else it will not detect the input file name instead of the list inside the input file.
    – web
    Nov 17, 2021 at 5:42
  • @they what does it mean by smallest in your context?
    – web
    Nov 17, 2021 at 5:42
  • @web Smallest = fewest lines.
    – Kusalananda
    Nov 17, 2021 at 7:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .