Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
 |
|
09-27-2005, 01:57 PM
|
#1
|
Member
Registered: May 2005
Location: uk - Reading
Distribution: slackware 14.2 kernel 4.19.43
Posts: 462
Rep:
|
processing command args in bash
#!/bin/bash noob here.
i'm comfortable with C but i think some simpler tasks on my system will be more easily achived with bash.
I'd also like to getter a better grasp of all my config files and initialisation scripts so here i go..
Code:
if [ "$#" -eq 0 ];then
echo "pls state the name of the file "
else
echo "on we go"
torrent=$#
echo $torrent # i wanted this to print out the name of the parsed cmd line arg 0:(
echo $1 #this obviously printed the name of the file i parsed at cmd line
fi
if [ -f $torrent ];then
echo "the file is here"
else
echo "no such file"
fi
pls see the comments in the middle of the code.
the program will process args of an indeterminate number but it will stipulate what
the last arg will be and thus i need acces to it,i.e test that it is there etc
i cant code [ -f $n .... where n is some integer value
because i will not know what the integer value will be ahead of time.
how do i achieve this pls?
|
|
|
Click here to see the post LQ members have rated as the most helpful post in this thread.
|
09-27-2005, 04:21 PM
|
#2
|
Senior Member
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536
Rep: 
|
Quote:
i cant code [ -f $n .... where n is some integer value
because i will not know what the integer value will be ahead of time.
how do i achieve this pls?
|
Code:
#!/bin/bash
# Processing of command line arguments in bash
# "shift" shifts all arguments to the left ($2=$1, $3=$2 etc.)
# "shift" returns non-zero exit-code (indicating "false")
# when no more arguments available.
# (note that $0 will not get "shifted").
ARGV0=$0 # First argument is shell command (as in C)
echo "Command: $ARGV0"
ARGC=$# # Number of args, not counting $0
echo "Number of args: $ARGC"
i=1 # Used as argument index
while true; do
if [ $1 ]; then
echo "Argv[$i] = $1" # Always print $1, shifting $2 into $1 later
shift
else
break # Stop loop when no more args.
fi
i=$((i+1))
done
echo "Done."
|
|
|
09-27-2005, 04:30 PM
|
#3
|
Senior Member
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536
Rep: 
|
Or, without "shift":
(" ${!i}" is actually the answer to your question "i cant code [ -f $n .... where n is some integer value")
Code:
#!/bin/bash
# Or, without "shift": use loop counter until $# ( = number of args)
ARGV0=$0 # First argument is shell command (as in C)
echo "Command: $ARGV0"
ARGC=$# # Number of args, not counting $0
echo "Number of args: $ARGC"
i=1 # Used as argument index
while [ $i -le $ARGC ]; do # "-le" means "less or equal", see "man test".
# "${!i} "expands" (resolves) to $1, $2,.. by first expanding i, and
# using the result (1,2,3..) as a variable which is then expanded.
echo "Argv[$i] = ${!i}"
i=$((i+1))
done
echo "Done."
Last edited by Hko; 09-27-2005 at 04:39 PM.
|
|
|
09-27-2005, 05:41 PM
|
#4
|
Member
Registered: Aug 2004
Location: a small village faraway in the mountains
Distribution: Fedora Core 1, Slackware 10.0 | 2.4.26 | custom 2.6.14.2, Slackware 10.2 | 11.0, Slackware64-13
Posts: 345
Rep:
|
Hey Slzckboy,
Didn't quite understand what you were trying to do. The first comment seemed to be confusing. But I guess your actual problem was parsing the last argument. Yes, the solution to that is using 'shift' or "${!i}" as Hko suggested. I guess you wanted this :
a) Invoke the script with n no. of arguments,
b) If n = 0 ask the user to input the name of the file, else
c) if n != 0 assume that the last argument is the name of a file, and check to see if that file exists or not.
Here's how the above script would look with shift :
Code:
#!/bin/bash
if [ "$#" -eq 0 ];then
echo "pls state the name of the file "
else
echo "on we go"
while [ "$2" != "" ]; do
shift
done
if [ -f $1 ];then
echo "Searching for file $1 : the file is here"
else
echo "Searching for file $1 : no such file"
fi
fi
exit 0
If there's something more you wanted please state that.
Hope this helps !
|
|
|
09-28-2005, 03:20 AM
|
#5
|
Member
Registered: May 2005
Location: uk - Reading
Distribution: slackware 14.2 kernel 4.19.43
Posts: 462
Original Poster
Rep:
|
no..thats fine . That is exactly what i meant.
thnks
|
|
|
09-28-2005, 04:36 AM
|
#6
|
Member
Registered: May 2005
Location: uk - Reading
Distribution: slackware 14.2 kernel 4.19.43
Posts: 462
Original Poster
Rep:
|
i think i will go the non "shift" way or else I will loose the data passed in on the previous args.!!?!
|
|
|
09-28-2005, 08:00 AM
|
#7
|
Senior Member
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,516
|
for parsing of command lines with flags,
man getopts
make life easy for yourself!
e.g parsing -d and -f flags, where -f requires an argument:
Code:
while getopts df: flag
do
case $flag in
d)
echo debugging on
;;
f)
file=$OPTARG
echo filename is $file
;;
?)
exit
;;
esac
done
shift $(( OPTIND - 1 )) # shift past the last flag or argument
echo parameters are $*
Result
Code:
$ bash opt.sh -df blah one two three
debugging on
filename is blah
parameters are one two three
$ bash opt.sh -f
opt.sh: option requires an argument -- f
$ bash opt.sh -r
opt.sh: illegal option -- r
Last edited by bigearsbilly; 09-28-2005 at 08:01 AM.
|
|
1 members found this post helpful.
|
09-28-2005, 10:51 AM
|
#8
|
Senior Member
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536
Rep: 
|
Quote:
Originally posted by slzckboy
i think i will go the non "shift" way or else I will loose the data passed in on the previous args.!!?!
|
...unless you store them in shell-variables of course.
|
|
|
09-28-2005, 11:04 AM
|
#9
|
Member
Registered: May 2005
Location: uk - Reading
Distribution: slackware 14.2 kernel 4.19.43
Posts: 462
Original Poster
Rep:
|
hmm...
ok..
well i'd value an opinion on what I have done thus far
i'm getting
"parameter passed in at end with no value" spat back at me.
Code:
#!/bin/sh
argv[0]=$0
bittorrent="btdownloadheadless.py"
# set default values
up_speed=2
min_port=49152
max_port=65535
if [ "$#" -eq 0 ];then
echo "pls state the name of the file"
exit 0
else
echo "on we go"
torrent=$#
fi
i=1
if [ -f "${!torrent}" ]; then
echo "${!torrent} file found"
while [ $i -lt $# ];do
case "${!i}" in
"--max_upload_rate")
i=$((i+1))
up_speed=${!i};;
esac
i=$((i+1))
done
exec /usr/local/bin/$bittorrent --max_upload_rate=$up_speed
else
echo "${!torrent} not found"
fi
basically wots wrong with doing.....
exec /usr/local/bin/$bittorrent --max_upload_rate=$up_speed ????
i tried "man getopts" but strangely the man page is not on my system.
will have to google 4 it.
|
|
|
09-28-2005, 02:06 PM
|
#10
|
Member
Registered: Aug 2004
Location: a small village faraway in the mountains
Distribution: Fedora Core 1, Slackware 10.0 | 2.4.26 | custom 2.6.14.2, Slackware 10.2 | 11.0, Slackware64-13
Posts: 345
Rep:
|
Quote:
Originally posted by slzckboy
i tried "man getopts" but strangely the man page is not on my system.
will have to google 4 it.
|
Try "man getopt" 
|
|
|
09-28-2005, 04:49 PM
|
#11
|
Member
Registered: May 2005
Location: uk - Reading
Distribution: slackware 14.2 kernel 4.19.43
Posts: 462
Original Poster
Rep:
|
hey ..
thnks 4 everyones help.
i have a working base now that I can expand on.
I have worked out the bugs in the above posted code
No need for getopts for now but I will keep it in mind for later use.
|
|
|
09-27-2017, 09:10 PM
|
#12
|
LQ Newbie
Registered: Sep 2017
Posts: 2
Rep: 
|
I'm having some trouble wrapping my head around the {!1} part. I love seeing different ways to do the same thing (comparing this to the earlier shift example) it really helps me gain a deeper understanding of said language (and programming in general).
ARGV[$i] is already the name so what different is the {$i} doing? Is it like command substitution?
I've done some research before asking and I've come across some info about hash keys, but I'm not sure that's really whats going on here. Thanks so much!
Quote:
Originally Posted by Hko
Or, without "shift":
(" ${!i}" is actually the answer to your question "i cant code [ -f $n .... where n is some integer value")
Code:
#!/bin/bash
# Or, without "shift": use loop counter until $# ( = number of args)
ARGV0=$0 # First argument is shell command (as in C)
echo "Command: $ARGV0"
ARGC=$# # Number of args, not counting $0
echo "Number of args: $ARGC"
i=1 # Used as argument index
while [ $i -le $ARGC ]; do # "-le" means "less or equal", see "man test".
# "${!i} "expands" (resolves) to $1, $2,.. by first expanding i, and
# using the result (1,2,3..) as a variable which is then expanded.
echo "Argv[$i] = ${!i}"
i=$((i+1))
done
echo "Done."
|
|
|
|
10-03-2017, 04:17 PM
|
#13
|
Bash Guru
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852
|
The problem to solve is that we need to access a parameter by name (number), without knowing the name in advance. We need to perform an indirect substitution, in other words.
The " ${!var}" pattern provides a way to do such indirect substitutions. It expands to the value of the variable given, then again to the value of the variable generated by it. So if " $2 = bar" and " i=2", then " ${!i}" will expand to " bar". Read the bash man page under Parameter Expansion for more detail.
Note, by the way, that bash does not automatically have an ARGV array, that's why a loop like the one above is (was) needed to iterate through and print all the values. The output produced by it would look like this:
Code:
Argv[1] = foo
Argv[2] = bar
Argv[3] = baz
Argv[4] = bum
Assuming those four words were fed to the script as arguments.
Frankly, though, I would've just used a simple c-style for loop instead:
Code:
for ((i=1;i<=$#;i++)); do echo "ARGV[$i] = ${!i}"; done
Actually, most of what's written here is rather outdated now. Today's bash has better tools available. You can now call arguments directly with ranges, for example:
Code:
echo "${@: -1}" # prints the last argument. Note that a space, or parentheses, is necessary for negative numbers.
echo "${@:(-2):2}" # prints the last two arguments.
There are also nameref variables that can provide more powerful indirection ability, although I'm not sure how useful they are in this specific case.
I myself would personally just go the simple route and copy the argument list into a new dedicated ARGV-style array. You can use both ranges and negative indexes that way.
Code:
ARGV=( "$0" "$@" )
echo "${ARGV[0]}"
echo "${ARGV[-1]}"
echo "${ARGV[@]: -1}"
echo "${ARGV[@]:(-2):2}"
With " ${ARGV[0]}" being the script name, naturally, and " ${ARGV[-1]}" being the last argument, just like " ${ARGV[@]: -1}", but also making it possible to apply an additional parameter expansion to the output (e.g. " ${ARGV[-1],,}" would lowercase the string at the same time).
Last edited by David the H.; 10-03-2017 at 04:34 PM.
Reason: fixed a code error and added some formatting
|
|
2 members found this post helpful.
|
10-03-2017, 04:48 PM
|
#14
|
LQ Newbie
Registered: Sep 2017
Posts: 2
Rep: 
|
That for loop makes it easier to see.
start at 1, until number of args, i++. Thanks
I'm taking it that these two lines are equivalent:
echo "${@: (-2):2}" # prints the last two arguments.
echo "${ARGV[@]: (-2):2}"
And in those lines the -2 is saying "start 2 back from the last" (the last is -1, the one before that is -2 so:
./argumentstuff.bash this that those many
many would be -1, so the -2 is starting at those.
Then the 2 thats after the -2 is saying do that to two items. so if it was ${@: (-2):1} would only delete "those"?
Last edited by tony4260; 10-03-2017 at 04:55 PM.
|
|
|
10-09-2017, 09:49 AM
|
#15
|
Member
Registered: Aug 2006
Location: Saint Paul, MN, USA
Distribution: {Free,Open}BSD, CentOS, Debian, Fedora, Solaris, SuSE
Posts: 735
Rep:
|
Hi.
Some additional sources that I have found useful:
Code:
Process command-line (CLI) options, arguments
1) getopts, builtin, bash, ksh, zsh
http://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-options
Also, search for option processing, including:
http://mywiki.wooledge.org/ComplexOptionParsing
2) perl: libgetopt-euclid-perl, creates man page, help automatically
3) getopt, enhanced getopts, part of the util-linux, allows GNU "--"
Examples: /usr/share/doc/util-linux/examples, 2016.03.27
4) argp.sh, wrapper for getopt, creates man and help (text, XML), etc.
Allows mixed options and arguments.
Compiled argp.c -> argp for faster execution.
https://sourceforge.net/projects/argpsh/, 2016.03.27
5) shflags, wrapper for getopt, creates help, allow mixed options
and arguments
https://github.com/kward/shflags, 2016.08.01
6) ksh getopts, enhanced, process GNU "--", creates man, help, etc.
Examples: Learning the Korn Shell, O'Reilly, 2nd, p 380ff
7) zsh zparseopts
man zshmodules, part of zshutil
8) Suggested option names:
http://www.shelldorado.com/goodcoding/cmdargs.html#flagnames
Best wishes ... cheers, makyo
|
|
|
All times are GMT -5. The time now is 02:55 AM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|