I am trying to write my first shell script for a class. The goal is to take a list of integers as a command line argument and display their squares and the sum of the squares. I am getting an error that the arguments are not being found.
This is the piece that is giving the error that the arguments are not found:
sumsq=0 #sum of squares
int=0 #Running sum initialized to 0
count=0 #Running count of numbers passed as arguments
while [ $# != 0 ]
do
numbers[$int]=`expr $1` #Assigns arguments to integers
let square=`expr $1*$1` #Operation to square arguments
squares[$int]=$square #Calc. square of each argument
sumsq=`expr $sumsq + $square` #Add square to total
count=`expr $count + 1` #Increment count
shift #Remove the used argument
int=`expr $int + 1` #Increment to next argument
done
I am using dash shell.
It seems that you are a bash beginner, some good pointers to start learning:
FAQ: http://mywiki.wooledge.org/BashFAQ
Guide: http://mywiki.wooledge.org/BashGuide
Ref: http://www.gnu.org/software/bash/manual/bash.html
http://wiki.bash-hackers.org/
http://mywiki.wooledge.org/Quotes
Check your script: http://www.shellcheck.net/
And avoid people saying to learn with tldp.org web site, the tldp bash guide is outdated, and in some cases just plain wrong.
There's many things in your code that can be improved. Better learn the good way as soon as possible. Your code looks 80's =)
A corrected version (not tested) with a more bashy way to do things:
sumsq=0 #sum of squares
int=0 #Running sum initialized to 0
count=0 #Running count of numbers passed as arguments
while (($# != 0 )); do
numbers[$int]=$1 #Assigns arguments to integers array
square=$(($1*$1)) #Operation to square argument first arg by itself
squares[$int]=$square #Square of each argument
sumsq=$((sumsq + square)) #Add square to total
count=$((count++)) #Increment count
shift #Remove the used argument
done
Dash doesn't support arrays, Bash does.
If you are running the script interactively you might not have bash configured as your default shell, run bash before trying.
If you are running it from console:
bash script.sh
If you are running it using its path (for example ./script.sh) ensure the first line of the script is:
#!/bin/bash
And not:
#!/bin/sh
Related
Im trying to take input from the terminal one line with spaces in between for example input would be something like this.
-1 -1 1
then im trying to take that input and add them together.
the catch is im only supposed to add positive integers so i need to remove the dashes.
I have
read Str
str=( $Str );
arr=${str//-/}
echo "$((${arr[#]/%/+}0))"
it seems like its only removing one instance of the dash and not the rest. Not sure which direction to take. Im sure there are multiple solutions.
Any help would be appreciated. I was also thinking maybe an If statement that could remove dashes before adding but not sure how exactly to even begin that.
If you just want to accumulate the words one at a time into a sum, removing any optional leading - characters, you can do that with something like:
read line
((sum = 0))
for num in ${line} ; do
absnum=${num//-/}
((sum += absnum))
done
echo "Sum is" ${sum}
Your method of removing leading negative sign is sound, but you don't really need to create an array to do the work. You can just iterate over the words as shown.
Keep in mind a real program should be a little more robust, handling non-numerics and such without falling in a screaming heap. You could do something like this immediately after the assignment to absnum:
[[ ! "${absnum}" =~ ^[1-9][0-9]*|0$ ]] && echo Bad number ${num} && exit 1
This would ensure it was a valid non-negative integer. A sample run follows so you can adjust to whatever test data you'd like to use:
pax> echo '3 0 --1 -2 4 40' | bash myscript.bash
Sum is 50
I came across the following while loop in a bash script tutorial online:
while(($#)) ; do
#...
shift
done
I don't understand the use of the positional parameter cardinality in the while loop. I know what the shift command does, but does the while statement have some special use in conjunction with shift?
Every time you do shift, the number of positional parameters is reduced by one:
$ set -- 1 2 3
$ echo $#
3
$ shift
$ echo $#
2
So this loop is executed until every positional parameter has been processed; (($#)) is true if there is at least one positional parameter.
A use case for doing this is (complex) option parsing where you might have options with an argument (think command -f filename): the argument to the option would be processed and removed with an additional shift.
For examples of complex option parsing, see BashFAQ/035 and ComplexOptionParsing. The last example of the second link, Rearranging arguments, uses the exact while (($#)) technique.
Let's have a script shi.sh:
while(($#)) ; do
echo "The 1st arg is: ==$1=="
shift
done
run it with:
bash shi.sh 1 2 3 #or chmod 755 shi.sh ; ./shi.sh 1 2 3
you will get
The 1st arg is: ==1==
The 1st arg is: ==2==
The 1st arg is: ==3==
Note the: 1st (and the usage of $1).
This is my first time using bash in college and it's being pretty hard now.
The exercise is:
Make a shell script which receives by parameter one word and a file list and adds the word in the beggining and ending of each file
So far what I've done is this:
#!bin/bash
word=$1;
i=2;
j=2;
for [ i -le $# ] in ls
do
for [ j -le $# ] in ls
do
if [ $i = $j ] then
$j=`word+$j+word`;
fi
done
done
and of course it doesn't work, but I really don't know why.
If anybody could help, it'd be great.
Sorry by any language mistake or convention in SO, I just arrived here. Thank you very much!
Since it's an exercise I'll give the answer in the way I would have wanted to learn about it:
Your script needs to take an arbitrary number of arguments - for example ./my_script.sh "my word" *.txt (note the space and quotes in the first parameter). There is a shell builtin command called shift which will remove the first argument from the argument list. The argument list is commonly referred to using "$#", but there is a handy shortcut syntax in Bash to loop over all arguments which avoids it entirely:
for argument
do
something with "$argument"
done
The exercise as originally stated says to add the string to the start and end of each file, not filename. There are plenty of examples of how to do that on this site and unix.SE.
You'll want to be careful about the difference between [ (aka. test) and [[.
Bash is not C - the ; command terminator is implicit at end of line (except of course in multi-line strings, here documents and the like).
Is it possible to create a script that will prompt a user to enter a number that will then programmatically be used for the number of arguments in a function/method? For example:
echo "Enter Number of arguments: "
read numOfArguments
Once a number is entered, this will stand for the number of parameters in a function. So if I enter 5, there should be 5 expected parameters within that method once called:
sampleMethod(){
...Takes 5 Parameters and actual code is here
}
sampleMethod ActualArgumentsfromPrompt
If this is possible can someone provide an example of how this is done? I am doing this because I would like to create a script that will parse through a log file but I need to pull specific items from the log that are set up similar to this: (0010,0020). The information I need will not always be a fixed number of items so that's why I would like to generate a prompt for a number of arguments.
Bash functions don't "expect" any number of arguments -- as you can see from the syntax, there's no list of parameter variables after the function name. They process arguments the same way the main shell does, by accessing them as $1, $2, etc. If you need to know how many arguments were passed, you can use $#.
To loop through all arguments, the common idiom is to process $1, then use shift to shift the argument list down.
sampleMethod() {
if [ $# -ne $numOfArguments ]
then echo Wrong number of arguments -$numOfArguments expected, $# provided >&2
return
fi
while [ $# -gt 0 ]; do
arg=$1
echo "$arg"
shift
done
}
I'm trying to write a shell program that, given an argument, prints the name of the program and every odd word in the argument (that is, not even words). However, I am not getting the expected result. Upon tracing my program, I notice that, despite modulus returning values of 1 on odd words (say, the 5th word, 5 % 2 = 1), the program still treats the result as 0 (an even word) and doesn't print the word. What might be going wrong here?
Included here is my code and the traced output to see exactly what I am getting. (Sorry for not including the code as text, I'm new to vim and don't know copy/paste yet)
$result (needs a dollar sign )
Change echo \$$# to echo $1. But it would probably be simpler to re-write the script:
#!/bin/sh
echo $0
while [ $# -gt 0 ]; do
expr $# % 2 > /dev/null && echo $1
shift
done