Shell script find occurrence of any character - bash

How can I find if a pattern has occurred in a variable in if condition.
Eg:
var1="DEFABCTY"
var2="EFGH"
How can I use if in shell script to find which of the two variables has "ABC" using if statement.

You can use pattern matching and variable indirection:
for var in var1 var2 ; do
if [[ ${!var} = *ABC* ]] ; then
echo ABC occurs in $var
fi
done

Related

Bash substitution inside substitution

I am learning bash, and wanted to do something very simple, here's my script:
#!/bin/bash
#read-multiple: reads multiple values from keyboard
echo -n "Enter one or more values:"
read var1 var2 var3 var4 var5
for i in {1..5}
do
echo var$i= ${var"$i"}
done
In the for loop I am trying to print to values entered by the user, only at the echoline I get the error:
${var"$i"}: bad substitution
What I was expecting to happen is:
$i expands to the current value between 1 and 5 (say 1 for example)
${var"$i"} expands to ${var1} which expands to the value of var1
This is not the case apparently...Could you explain to me why that is ? does bash expand everything on the line at once?
I have also tried ${var${$i}} and $var${$i} but both give the same error...why is that ?
You could do this:
for v in var{1..5}; do
echo $v = ${!v}
done
or
for i in {1..5}; do
v="var$i"
echo $v = ${!v}
done
See this post:
What is indirect expansion? What does ${!var*} mean?
Documentation here:
Shell Parameter Expansion

Extract variables values from command output Bash Shell

In bash shell I have a command that prints variable name and values such as:
Hello mate this is you variables:
MY_VAR1= this is the value of the first var
MY_VAR2= subvar1=27, subvar2=hello1
Have a good day!
The value of the variables in the output can contain characters as =,commas,;,:.., but I expect to find new line at the end of each variable value.
I need to create a short script which reads the values of MY_VAR1 and MY_VAR2.
So I need to end up with 2 variables as follows:
MY_VAR1 = this is the value of the first var
MY_VAR2 = subvar1=27, subvar2=hello1
I have a basic installation of CentOS 7, and I can't install additional stuff in that machine.
How can I achieve it?
I assume that the variable names are everything from the beginning of the lines, up to the = sign (excluded) with leading and trailing blanks removed (you cannot have blanks in your variable names).
If all you want is print the output you show, you can use something like:
while read line; do
if [[ $line =~ ^[[:blank:]]*([^[:blank:]]+)[[:blank:]]*=(.*)$ ]]; then
var="${BASH_REMATCH[1]}"
val="${BASH_REMATCH[2]}"
echo "$var = $val"
fi
done < <( my_command )
The =~ operator is a pattern matching with regular expressions. The regular expression ^[[:blank:]]*([^[:blank:]]+)[[:blank:]]*=(.*)$ models an output line of your command with variable assignment. It matches even if the variable name is surrounded with blanks. Two sub-expressions (enclosed in ()) are isolated: the variable name and the value. The BASH_REMATCH array contains the patterns that matched the sub-expressions in cells 1 and 2, respectively.
If you also want to assign the variables:
while read line; do
if [[ $line =~ ^[[:blank:]]*([^[:blank:]]+)[[:blank:]]*=(.*)$ ]]; then
var="${BASH_REMATCH[1]}"
val="${BASH_REMATCH[2]}"
echo "$var = $val"
declare $var="$val"
fi
done < <( my_command )

How to extract a substring from a URL in bash

I have the following string
git#bitbucket.org:user/my-repo-name.git
I want to extract this part
my-repo-name
With bash:
s='git#bitbucket.org:user/my-repo-name.git'
[[ $s =~ ^.*/(.*)\.git$ ]]
echo ${BASH_REMATCH[1]}
Output:
my-repo-name
Another method, using bash's variable substitution:
s='git#bitbucket.org:user/my-repo-name.git'
s1=${s#*/}
echo ${s1%.git}
Output:
my-repo-name
I'm not sure if there's a way to combine the # and % operators into a single substitution.

In a function Bash: how to check if an argument is a set variable?

I want to implement a bash function which test is the 1st argument is actually a variable, defined somewhere.
For instance, in my .bashrc :
customPrompt='yes';
syntaxOn='no';
[...]
function my_func {
[...]
# I want to test if the string $1 is the name of a variable defined up above
# so something like:
if [[ $$1 == 'yes' ]];then
echo "$1 is set to yes";
else
echo "$1 is not set or != to yes";
fi
# but of course $$1 doesn't work
}
output needed :
$ my_func customPrompt
> customPrompt is set to yes
$ my_func syntaxOn
> syntaxOn is set but != to yes
$ my_func foobar
> foobar is not set
I tried a lot of test, like -v "$1", -z "$1", -n "$1", but all of them test $1 as a string not as a variable.
(please correct me if I make not myself clear enought)
In the bash you can use the indirect variable subtituion.
t1=some
t2=yes
fufu() {
case "${!1}" in
yes) echo "$1: set to yes. Value: ${!1}";;
'') echo "$1: not set. Value: ${!1:-UNDEF}";;
*) echo "$1: set to something other than yes. Value: ${!1}";;
esac
}
fufu t1
fufu t2
fufu t3
prints
t1: set to something other than yes. Value: some
t2: set to yes. Value: yes
t3: not set. Value: UNDEF
The ${!variablename} in bash mean indirect variable expansion. Described in the e.g. https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
Whrere:
The basic form of parameter expansion is ${parameter}. The value of
parameter is substituted. The braces are required when parameter is a
positional parameter with more than one digit, or when parameter is
followed by a character that is not to be interpreted as part of its
name.
If the first character of parameter is an exclamation point (!), a
level of variable indirection is introduced. Bash uses the value of
the variable formed from the rest of parameter as the name of the
variable; this variable is then expanded and that value is used in the
rest of the substitution, rather than the value of parameter itself.
This is known as indirect expansion. The exceptions to this are the
expansions of ${!prefix } and ${!name[#]} described below. The
exclamation point must immediately follow the left brace in order to
introduce indirection.
Also, check this: https://stackoverflow.com/a/16131829/632407 how to modify in a function a value of the variable passed indirectly.
You can check variable set or not by simply like
if [[ $var ]]
then
echo "Sorry First set variable"
else
echo $var
fi
You can do something like this for your script
customPrompt='yes';
syntaxOn='no';
function my_func
{
if [[ ${!1} ]];then
echo "$1 is set to ${!1}";
else
echo "$1 is not set";
fi
}
my_func customPrompt
my_func syntaxOn
my_func foobar
Output:
customPrompt is set to yes
syntaxOn is set to no
foobar is not set
You can customize the function as per you requirement by simply making some comparison conditions.
For more details you can check this answer
If you really want to check if your variable is set or unset (not just empty), use this format:
function my_func {
if [[ -z ${!1+.} ]]; then
echo "$1 is not set."
elif [[ ${!1} == yes ]]; then
echo "$1 is set to yes"
else
echo "$1 is set to \"${!1}\"."
fi
}
You're going to have problems...
The Bash shell is a very wily creature. Before you execute anything, Bash comes in and interpolates your command. Your command or shell script never sees whether or not you have a variable as a parameter.
$ set -x
set -x
$ foo=bar
+ foo=bar
$ echo "$foo"
+ echo bar
bar
$ set +x
The set -x turns on debugging mode in the shell. It shows you what a command actually executes. For example, I set foo=bar and then do echo $foo. My echo command doesn't see $foo. Instead, before echo executes, it interpolates $foo with bar. All echo sees at this point is that it's suppose to take bar as its argument (not $foo).
This is awesomely powerful. It means that your program doesn't have to sit there and interpret the command line. If you typed echo *.txt, echo doesn't have to expand *.txt because the shell has already done the dirty work.
For example, here's a test shell script:
#! /bin/sh
if [[ $1 = "*" ]]
then
echo "The first argument was '*'"
else
"I was passed in $# parameters"
fi
Now, I'll run my shell script:
$ test.sh *
I was passed in 24 parameters
What? Wasn't the first parameter of my script a *? No. The shell grabbed * and expanded it to be all of the files and directories in my directory. My shell script never saw the *. However, I can do this:
$ test.sh '*'
The first argument was '*'
The single quotes tell the shell not to interpolate anything. (Double quotes prevent globbing, but still allow for environment variable expansion).
This if I wanted to see if my first parameter is a variable, I have to pass it in single quotes:
$ test.sh '$foo'
And, I can do this as a test:
if [[ $1 != ${1#$} ]]
then
echo "The first parameter is the variable '$1'"
fi
The ${1#$} looks a bit strange, but it's just ${var#pattern}. This removes pattern from the left most side of $var. I am taking $1 and removing the $ if it exists. This gets expanded in the shell as:
if [[ $foo != foo ]]
which is true.
So, several things:
First, you've got to stop the shell from interpolating your variable. That means you have to use single quotes around the name.
You have to use pattern matching to verify that the first parameter starts with a $.
Once you do that, you should be able to use your variable with ${$1} in your script.

Comparing variables in shell scripts

I have got a project that involves shell scripts and comparing values/variables within them. I have looked here and elsewhere on comparing variables and I have tried all the various examples given but I am running into something that is not as advertised. OS is Solaris10
I have created the following script as a learning experience-
#!/bin/ksh
stest()
{
if $X = $Y
then echo they're the same
else echo they're notthe same
fi
}
X=a
Y=a
stest
echo completed
I keep getting some variation of the following-
using shell sh or ksh-
#./test.sh
./test.sh[2]: a: not found
completed
using shell bash-
#./test.sh
./test.sh: line 5: a: command not found
completed
I have tried enclosing the if $X = $Y line in brackets and double brackets and I get back
[a: not found
or
[[a: not found
If I change the variables X and Y to the numeral "1" I get the same thing-
./test.sh[2]: 1: not found
I have tried enclosing things in single quotes, double quotes & backwards quotes.
Any help is appreciated.
After if, you need a shell command, like anywhere else. $X = $Y is parsed as a shell command, meaning $X is interpreted as a command name (provided that the value of the variable is a single word).
You can use the [ command (also available as test) or the [[ … ]] special syntax to compare two variables. Note that you need spaces on the inside of the brackets: the brackets are a separate token in the shell syntax.
if [ "$X" = "$Y" ]; then …
or
if [[ "$X" = "$Y" ]]; then …
[ … ] works in any shell, [[ … ]] only in ksh, bash and zsh.
Note that you need double quotes around the variables¹. If you leave off the quotes, then the variable is split into multiple words and each word is interpreted as a wildcard pattern. This doesn't happen inside [[ … ]], but the right-hand side of = is interpreted as a wildcard pattern there too. Always put double quotes around variable substitutions (unless you want the value of the variable to be used as a list of filename matching patterns, rather than as a string).
¹ Except on $X the [[ … ]] syntax.
This KornShell (ksh) script should work:
soExample.ksh
#!/bin/ksh
#Initialize Variables
X="a"
Y="a"
#Function to create File with Input
#Params: 1}
stest(){
if [ "${X}" == "${Y}" ]; then
echo "they're the same"
else
echo "they're not the same"
fi
}
#-----------
#---Main----
#-----------
echo "Starting: ${PWD}/${0} with Input Parameters: {1: ${1} {2: ${2} {3: ${3}"
stest #function call#
echo "completed"
echo "Exiting: ${PWD}/${0}"
Output :
user#foo:/tmp $ ksh soExample.ksh
Starting: /tmp/soExample.ksh with Input Parameters: {1: {2: {3:
they're not the same
completed
Exiting: /tmp/soExample.ksh
ksh version:
user#foo:/tmp $ echo $KSH_VERSION
#(#)MIRBSD KSH R48 2013/08/16

Resources