Issues storing arguments from getopts in shell script - bash

I am new using unix and I recently tried to create a code that would take some arguments and pass it to a python script and later use those arguments for downstream processes.
I am trying to use getopts but after I tried running the script it looks like my arguments were not stored in variables and anything downstream failed.
This is a piece of what I tried so far
#!/bin/bash
function usage() {
cat <<USAGE
Usage: $0 [-f fasta] [-o output name] [-m memory] [-t time] [-n number of tasks] [-c cores] [-g gpus] [-e extra]
Options:
-f fasta file
-o output name
-m memory to request
-t time to request
-n number of tasks
-c cores to request
-g gpus to request - no more than 4!
-e extra arguments for program
USAGE
}
while getopts ":f:o:m:t:n:c:g:e:h" flag
do
case "${flag}" in
f)
fasta=${OPTARG}
;;
o)
out_name=${OPTARG}
;;
m)
memory=${OPTARG}
;;
t)
time=${OPTARG}
;;
n)
number=${OPTARG}
;;
c)
cores=${OPTARG}
;;
g)
gpus=${OPTARG}
;;
e)
extra=${OPTARG}
;;
h)
usage
;;
:)
echo "Invalid option: $OPTARG" 1>&2
usage
exit 1
;;
\?)
echo "Invalid option"
usage
exit 1
;;
esac
done
python3 /scratch/amolinav/programs/my_script_single.py ${fasta} ${out_name} ${memory} ${time} ${number} ${cores} ${gpus} ${extra}
I would really appreciate if someone could point out where I am making the mistake.
Thank you so much in advance for your help

Related

Cannot convert string '=' to double (m_Pos = 0) error in bash

I want to give a numerical value as input argument for a bash script which is as below
#!/bin/bash
while getopts ":hl:q:s:e:k:g:v" opt; do
case $opt in
l)
lincRNAfasta=$OPTARG
;;
q)
query_species=$OPTARG
;;
s)
subject_species=$OPTARG
;;
e)
subject_gff=$OPTARG
;;
g)
subject_genome=$OPTARG
;;
k)
known_lincRNAs=$OPTARG
;;
v)
evalue=$OPTARG
;;
h)
usage
exit 1
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
echo "Starting on $subject_species"
# Formatting the genome
makeblastdb -logfile stderr.out -in $subject_genome -dbtype nucl -out BLAST_DB/$subject_genome.blast.out
# Blasting the lincRNA transcripts against the genome to find out the location on the genome And identify if there are any paralogs in the query genome.
blastn -logfile stderr.out -query $lincRNAfasta -db BLAST_DB/$subject_genome.blast.out -num_threads 4 -penalty -2 -reward 1 -gapopen 5 -gapextend 2 -dust no -word_size 8 -evalue $evalue -outfmt "6 qseqid sseqid pident length qlen qstart qend sstart send evalue bitscore" -out Homology_Search/$subject_species.out
When i run the above script like this:
sh test.sh -l sample.data/Hsap_lincRNAs.fasta -q Hsap -s Hsap -e sample.data/Hsap_genes.gff -g sample.data/Hsap_genome.fasta -k sample.data/Hsap_lincRNAs -v 1e-20
I get this following error.
Error: Cannot convert string '=' to double (m_Pos = 0)
Error: Argument "evalue". Argument cannot be converted: `='
Error: (CArgException::eConvert) Argument "evalue". Argument cannot be converted: `='
I have never run a numeric value as argument with the getopts module in bash and so i am not sure what am i doing wrong here. Any help is much appreciated.
Thanks
Upendra

Bash long options/flags - how to do it?

I am trying to change my working script with getopts to getopt ( long flags ).
Below i present my code which is working.
getopts 'm:' mode
modeValue=$OPTARG
getopts 'p:' parameter
parameterValue=$OPTARG
getopts 'u:' parameter
parameterValue2=$OPTARG
getopts 'l:' parameter
parameterValue3=$OPTARG
getopts 'n:' parameter
parameterValue4=$OPTARG
getopts 'e:' parameter
parameterValue5=$OPTARG
getopts 'w:' parameter
parameterValue6=$OPTARG
getopts 'r:' parameter
parameterValue7=$OPTARG
case $modeValue in
addRepository)
doAddRepository "$parameterValue" "$parameterValue7"
exit $?
;;
addProject)
doAddProject "$parameterValue"
exit $?
;;
addUser)
doAddUser "$parameterValue2" "$parameterValue4" "$parameterValue5" "$parameterValue6"
exit $?
;;
assignProject)
doAssignProject "$parameterValue" "$parameterValue2" "$parameterValue3"
exit $?
;;
*)
#echo "$doShowUsage"
exit 1
;;
esac
Now my script is working like example below:
For add repository: ./script.sh -m addRepository -p NameOfTheProject -r NameOfTheRepository
I want to edit this for something like this:
./script.sh --mode addRepository --project NameOfTheProject --repo NameOfTheRepository
I started to modify code and added something what i present below:
TEMP=`getopt -o m:p:u:l:n:e:c:r: --long mode:,project:,username:,level:,name:,email:,pass:,repo: -n 'test.sh'
-- "$#"` eval set -- "$TEMP"
while true ; do
case "$1" in
-m|--mode)
case "$2" in
addRepository)
doAddRepository=$2 ; shift 2 ;;
addProject)
doAddProject=$2 ; shift 2 ;;
addUser)
doAddUser=$2 ; shift 2 ;;
assignProject)
doAssignProject=$2 ; shift 2 ;;
esac ;;
-h|--help)
case "$2" in
*) echo "$doShowUsage"
exit 1
esac ;;
esac done
My question is : Am I doing it in the right way ? How can I add parameters to the functions "doAddProject/Repository/User...?" Can someone give me some advices? Above functions got different amount of parameters so take a look at it.
Thank you!
Stephane Chazelas wrote a very fine getops-long shell script that I use in my bash debugger. You can copy that script and use it.
If you run that program setting variable test_getopts_long, e.g.
test_getopts_long=1 bash getopts_long.sh
you'll see extensive examples for how to use, and it tests itself.

Execution sequence in shell script and passing the right arguments to functions

I have a shell script that I use to launch some ROS launcher file (not that important for my question). My requirement is to use some arguments and therefore I am using getopts.
Basically, I am getting one file or a few, playing them with ROS and simultaneously recording all the files back to a single file. After that, if I have provided an argument -r or -c, I would like to run two additional operations (reindex and compress) on the recorded file. But it is required that the other process are done, before I can run the -r and -c. I am using the wait keyword, but I am not sure I really understand the flow. In other words, the playing and recording should be done and only then -r and -c should be run if provided as arguments.
Second question is related to how do I get or pass the same file that was outputted to these two functions (reindex and compress)?
So my desired format is:
./myscript -i file1 -i file2 -o /home/output -r -c
#!/bin/bash
OUTPUT_FILE_NAME="output_$(date +%Y.%m.%d--%H_%M_%S)"
usage="
$(basename "$0") [-i] [-o] [-r] [-c] [-h] -- to be done"
# Reset is necessary if getopts was used previously in the script.
OPTIND=1
while getopts ":i:orch:" opt; do
case $opt in
i ) echo "INPUT file - argument = $OPTARG"; input_files+=($OPTARG) ;;
o ) echo "OUTPUT dir - argument = $OPTARG"; output_dir=($OPTARG) ;;
r ) echo "REINDEX"; reindex ;;
c ) echo "COMPRESS"; compress ;;
h ) echo "$usage"
graceful_exit ;;
* ) echo "$usage"
exit 1
esac
done
# Shift off the options
shift $((OPTIND-1))
roslaunch myLauncher.launch &
echo "Number of loaded files: ${#input_files[#]}"
echo -n "FILES are:"
rosbag play ${input_files[#]} &
rosbag record -o $output_dir/$OUTPUT_FILE_NAME -a &
wait
function reindex{
rosbag reindex $output_dir/$OUTPUT_FILE_NAME
}
function compress{
rosbag reindex $output_dir/$OUTPUT_FILE_NAME
}
Thank you in advance!
You're very close to where you need to be — and using getopts puts you firmly on the correct track, too. Note whether or not you need to reindex or compress in the option parsing loop. Then, after the music has been played and the output file written, run the code from the functions if you need to:
#!/bin/bash
OUTPUT_FILE_NAME="output_$(date +%Y.%m.%d--%H_%M_%S)"
usage="$(basename "$0") [-i file] [-o file] [-r] [-c] [-h]"
input_files=() # Empty list of files/tracks
output_dir="." # Default output directory
r_flag="no" # No reindex by default
c_flag="no" # No compress by default
while getopts ":i:orch:" opt; do
case $opt in
(i) echo "INPUT file - argument = $OPTARG"; input_files+=("$OPTARG");;
(o) echo "OUTPUT dir - argument = $OPTARG"; output_dir="$OPTARG";;
(r) echo "REINDEX"; r_flag="yes";;
(c) echo "COMPRESS"; c_flag="yes";;
(h) echo "$usage" >&2; exit 0;;
(*) echo "$usage" >&2; exit 1;;
esac
done
# Shift off the options
shift $((OPTIND-1))
if [ $# != 0 ] || [ "${#input_files[#]}" = 0 ] ||
then
echo "$usage" >&2
exit 1
fi
roslaunch myLauncher.launch &
echo "Number of loaded files: ${#input_files[#]}"
echo -n "FILES are:"
rosbag play "${input_files[#]}" &
rosbag record -o "$output_dir/$OUTPUT_FILE_NAME" -a &
wait
if [ "$r_flag" = "yes" ]
then
rosbag reindex "$output_dir/$OUTPUT_FILE_NAME"
fi
if [ "$c_flag" = "yes" ]
then
rosbag compress "$output_dir/$OUTPUT_FILE_NAME"
fi
I didn't keep the functions since they didn't provide any value in the rewritten code.

Can't assign a value to a variable in a case statement in bash

I just ran into a problem while I was trying to assign a value to a variable inside a case statement, here is my code:
#!/bin/bash
while getopts ":m:n:::" opt; do
case $opt in
n)
echo "-n was triggered, Parameter: $OPTARG " >&2
case $OPTARG in
t)
echo threads
r=threads
;;
p)
echo processes
r="something"
;;
esac
;;
m)
echo "-m was triggered, Parameter: $OPTARG" >&2
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
echo $r
echo No thread/processes: $2 P/T: $4 IF: $5 OF: $6
I'd like to use the variable $r later, but I can't. When I try to print it using echo (as it is in my script), it does not return a thing.
I've been trying to spot my mistake but I couldn't.
There is a similar post that suggested to remove blank spaces before and after the =, but as you can see, there are no blank spaces in mine.
Here is what I get from the console when I run it:
$ ./friendfind -n 2 -m p IN OUT
-n was triggered, Parameter: 2
-m was triggered, Parameter: p
No thread/processes: 2 P/T: p IF: IN OF: OUT
The purpose of the script was to run a c file with the option to run it with threads or processes, so it asks for the number of processes/threads you want to use, if you want to tu use processes or threads and the input and output file.
I think you were aiming at something like this:
#!/bin/bash
# Print usage message:
usage() {
echo "Usage: $0 [-n N] [-t|-p] INPUT OUTPUT" >> /dev/stdout
}
# Set default values
n_threads=1
use_threads=1
while getopts "n:pth" opt; do
case $opt in
n) n_threads=$OPTARG;;
t) use_threads=1;;
p) use_threads=0;;
h) usage; exit 0;;
*) usage; exit 1;;
esac
done
# Get rid of scanned options
shift $((OPTIND-1))
if (($# != 2)); then usage; exit 1; fi
if ((use_threads)); then
echo "Using $n_threads threads. IF: $1; OF: $2"
# ...
else
echo "Using $n_threads processes. IF: $1; OF: $2"
# ...
fi
Here's some example invocations, including a couple of errors:
$ ./ff -p foo bar
Using 1 processes. IF: foo; OF: bar
$ ./ff foo bar
Using 1 threads. IF: foo; OF: bar
$ ./ff -n 7 foo bar
Using 7 threads. IF: foo; OF: bar
$ ./ff -n 7 -p foo bar
Using 7 processes. IF: foo; OF: bar
$ ./ff -p -n7 foo bar
Using 7 processes. IF: foo; OF: bar
$ ./ff -q -n7 foo bar
./ff: illegal option -- q
Usage: ./ff [-n N] [-t|-p] INPUT OUTPUT
# Note: The error message here could be more informative.
# Exercise left for the reader
$ ./ff -n 7 foo
Usage: ./ff [-n N] [-t|-p] INPUT OUTPUT

Getopts not properly parsing arguments

I have following shell script -
while getopts “h:f:p:u” OPTION
do
case $OPTION in
h)
usage
exit 1
;;
f)
FILE=$OPTARG
;;
u)
US=$OPTARG
;;
p)
PASSWD=$OPTARG
;;
?)
usage
exit
;;
esac
done
echo "$FILE"
echo "$PASSWD"
echo "$US"
I use following commandline arguments -
-u root -f mydb -p h2
There is no output on screen. Why?
Your call to getopt should look like this ...
while getopts “hf:p:u:” OPTION
... because h takes no args and the other options do.
It should be while getopts “hf:p:u:” OPTION

Resources