bash shell script concatenate string with period char - string

I am trying to create following string
Beta-3.8.0
but shell script always omits the . period char no matter what I do.
echo "$readVersion"
if [ -z $readVersion ]
then
echo "readVersion is empty"
exit 1
fi;
IFS=.
set $readVersion
newVersion=$(echo "$2 + 1" | bc)
newBranch="Beta-$1.$newVersion.$3"
echo $newBranch
prints:
3.8.0
Beta-3 9 0
I have also tried
newBranch='Beta-'$1'.'$newVersion'.'$3
or
newBranch="Beta-{$1}.{$newVersion}.{$3}"
although this seems printing the right value echo "$1.$newVersion.$3" why not variable doesnt work ?
I need the variable to use later on in the script...

You can save and restore the IFS once you are done.
oldIFS=$IFS
IFS=.
set $readVersion
newVersion=$(echo "$2 + 1" | bc)
IFS=$oldIFS
newBranch="Beta-$1.$newVersion.$3"
echo "$newBranch"
Or you can quote when printing:
echo "$newBranch"
The former is a better idea IMO since it conveys your intention and would make the rest of the code use the "correct" IFS. The latter just circumvents the problem.

Related

Why is this Bash variable empty? [duplicate]

I have a Bash script where I want to count how many things were done when looping through a file. The count seems to work within the loop but after it the variable seems reset.
nKeys=0
cat afile | while read -r line
do
#...do stuff
let nKeys=nKeys+1
# this will print 1,2,..., etc as expected
echo Done entry $nKeys
done
# PROBLEM: this always prints "... 0 keys"
echo Finished writing $destFile, $nKeys keys
The output of the above is something alone the lines of:
Done entry 1
Done entry 2
Finished writing /blah, 0 keys
The output I want is:
Done entry 1
Done entry 2
Finished writing /blah, 2 keys
I am not quite sure why nKeys is 0 after the loop :( I assume it's something basic but damned if I can spot it despite looking at http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-7.html and other resources.
Fingers crossed someone else can look at it and go "well duh! You have to ..."!
In the just-released Bash 4.2, you can do this to prevent creating a subshell:
shopt -s lastpipe
Also, as you'll probably see at the link Ignacio provided, you have a Useless Use of cat.
while read -r line
do
...
done < afile
As mentioned in the accepted answer, this happens because pipes spawn separate subprocesses. To avoid this, command grouping has been the best option for me. That is, doing everything after the pipe in a subshell.
nKeys=0
cat afile |
{
while read -r line
do
#...do stuff
let nKeys=nKeys+1
# this will print 1,2,..., etc as expected
echo Done entry $nKeys
done
# PROBLEM: this always prints "... 0 keys"
echo Finished writing $destFile, $nKeys keys
}
Now it will report the value of $nKeys "correctly" (i.e. what you wish).
I arrived at the desired result in the following way without using pipes or here documents
#!/bin/sh
counter=0
string="apple orange mango egg indian"
str_len=${#string}
while [ $str_len -ne 0 ]
do
c=${string:0:1}
if [[ "$c" = [aeiou] ]]
then
echo -n "vowel : "
echo "- $c"
counter=$(( $counter + 1 ))
fi
string=${string:1}
str_len=${#string}
done
printf "The number of vowels in the given string are : %s "$counter
echo

Script not working getting a "Not Valid Identifier"

Am doing this for a class, but am having issues with it. I am new to Linux and really having a hard time. Am trying input 3 values (M, R, T), figure out if they are greater, less than or equal to 2000 and print a statement. Not sure I am doing it right. I get the questions and can input, but am not sure if it is completely working.
#!/bin/sh
clear
echo -n "What is the value of M?"
read $M
sleep 3
echo -n "What is the value of R?"
read $R
echo -n "What is the value of T?"
read $T
A=$M+$R+$T
if [ $A > "2000" ]
then
echo "A is over 2000"
else
echo "A is 2000 or less"
fi
There's a few things wrong here. Firstly, read takes the name of the variable without the $. Secondly, you can specify a prompt on the same line, so no need for all the separate echos. Thirdly, in order to do a numerical comparison, you should be using -gt:
#!/bin/sh
clear
read -p "What is the value of M?" M
sleep 3
read -p "What is the value of R?" R
read -p "What is the value of T?" T
A=$((M+R+T)) # different syntax here too
if [ "$A" -gt 2000 ]
then
echo "A is over 2000"
else
echo "A is 2000 or less"
fi
If you are using bash, another way to compare integers in bash is to use an arithmetic context:
if (( A > 2000 ))
Remember to change the shebang to #!/bin/bash if you want to use bash features.

looking for a command to tentatively execute a command based on criteria

I am looking for a command (or way of doing) the following:
echo -n 6 | doif -criteria "isgreaterthan 4" -command 'do some stuff'
The echo part would obviously come from a more complicated string of bash commands. Essentially I am taking a piece of text from each line of a file and if it appears in another set of files more than x (say 100) then it will be appended to another file.
Is there a way to perform such trickery with awk somehow? Or is there another command.. I'm hoping that there is some sort of xargs style command to do this in the sense that the -I% portion would be the value with which to check the criteria and whatever follows would be the command to execute.
Thanks for thy insight.
It's possible, though I don't see the reason why you would do that...
function doif
{
read val1
op=$1
val2="$2"
shift 2
if [ $val1 $op "$val2" ]; then
"$#"
fi
}
echo -n 6 | doif -gt 3 ls /
if test 6 -gt 4; then
# do some stuff
fi
or
if test $( echo 6 ) -gt 4; then : ;fi
or
output=$( some cmds that generate text)
# this will be an error if $output is ill-formed
if test "$output" -gt 4; then : ; fi

How to detect spaces in shell script variable [duplicate]

This question already has answers here:
How to check if a string has spaces in Bash shell
(10 answers)
Closed 3 years ago.
e.g string = "test test test"
I want after finding any occurance of space in string, it should echo error and exit else process.
The case statement is useful in these kind of cases:
case "$string" in
*[[:space:]]*)
echo "argument contains a space" >&2
exit 1
;;
esac
Handles leading/trailing spaces.
There is more than one way to do that; using parameter expansion
you could write something like:
if [ "$string" != "${string% *}" ]; then
echo "$string contains one or more spaces";
fi
For a purely Bash solution:
function assertNoSpaces {
if [[ "$1" != "${1/ /}" ]]
then
echo "YOUR ERROR MESSAGE" >&2
exit 1
fi
}
string1="askdjhaaskldjasd"
string2="asjkld askldja skd"
assertNoSpaces "$string1"
assertNoSpaces "$string2" # will trigger error
"${1/ /}" removes any spaces in the input string, and when compared to the original string should be exactly the same if there are not spaces.
Note the quotes around "${1/ /}" - This ensures that leading/trailing spaces are taken into consideration.
To match more than one character, you can use regular expressions to define a pattern to match - "${1/[ \\.]/}".
update
A better approach would be to use in-process expression matching. It will probably be a wee bit faster as no string manipulation is done.
function assertNoSpaces {
if [[ "$1" =~ '[\. ]' ]]
then
echo "YOUR ERROR MESSAGE" >&2
exit 1
fi
}
For more details on the =~ operator, see the this page and this chapter in the Advanced Bash Scripting guide.
The operator was introduced in Bash version 3 so watch out if you're using an older version of Bash.
update 2
Regarding question in comments:
how to handle the code if user enter
like "asd\" means in double quotes
...can we handle it??
The function given above should work with any string so it would be down to how you get input from your user.
Assuming you're using the read command to get user input, one thing you need to watch out for is that by default backslash is treated as an escape character so it will not behave as you might expect. e.g.
read str # user enters "abc\"
echo $str # prints out "abc", not "abc\"
assertNoSpaces "$str" # no error since backslash not in variable
To counter this, use the -r option to treat backslash as a standard character. See read MAN Page for details.
read -r str # user enters "abc\"
echo $str # prints out "abc\"
assertNoSpaces "$str" # triggers error
The == operator inside double brackets can match wildcards.
if [[ $string == *' '* ]]
You can use grep as:
string="test test test"
if ( echo "$string" | grep -q ' ' ); then
echo 'var has space'
exit 1
fi
I just ran into a very similar problem while handling paths. I chose to rely on my shell's parameter expansion rather than looking for a space specifically. It does not detect spaces at the front or the end, though.
function space_exit {
if [ $# -gt 1 ]
then
echo "I cannot handle spaces." 2>&1
exit 1
fi
}

shell script to compare files and print formatted output

I'm trying to write a shell script which will compare two files, and if there are no differences between then, it will indicate that there was a success, and if there are differences, it will indicate that there was a failure, and print the results. Here's what I have so far:
result = $(diff -u file1 file2)
if [ $result = "" ]; then
echo It works!
else
echo It does not work
echo $result
fi
Anybody know what I'm doing wrong???
result=$(diff -u file1 file2)
if [ $? -eq 0 ]; then
echo "It works!"
else
echo "It does not work"
echo "$result"
fi
Suggestions:
No spaces around "=" in the variable assignment for results
Use $? status variable after running diff instead of the string length of $result.
I'm in the habit of using backticks for command substitution instead of $(), but #Dennis Williamson cites some good reasons to use the latter after all. Thanks Dennis!
Applied quotes per suggestions in comments.
Changed "=" to "-eq" for numeric test.
First, you should wrap strings being compared with quotes.
Second, "!" cannot be use it has another meaning. You can wrap it with single quotes.
So your program will be.
result=$(diff -u file1 file2)
if [ "$result" == "" ]; then
echo 'It works!'
else
echo It does not work
echo "$result"
fi
Enjoy.
Since you need results when you fail, why not simply use 'diff -u file1 file2' in your script? You may not even need a script then. If diff succeeds, nothing will happen, else the diff will be printed.
bash string equivalence is "==".
-n is non-zero string, -z is zero length string, wrapping in quotes because the command will complain if the output of diff is longer than a single string with "too many arguments".
so
if [ -n "$(diff $1 $2)" ]; then
echo "Different"
fi
or
if [ -z "$(diff $1 $2)" ]; then
echo "Same"
fi

Resources