I'm writing a script that asks the user for several options and then, via a series of echo statements, creates and writes to a separate script file. That script will also be dependent on at least one command line argument when executed.
Given the original statement
if [ "` echo $1 | egrep ^[[:digit:]]+$`" = "" ]
that determines if the first argument ($1) is an integer, how can I include that in the echo statement to be written to the new file while maintaining the command line argument access?
I tried to escape the double quotes and dollar signs like
echo "if [ \"` echo \$1 | egrep ^[[:digit:]]+\$`\" = \"\" ]" >> generatePanos
but that just resulted in
if [ "" = "" ]
However, echo "\$1" results in $1 being printed in the file.
Since you are using bash, you can use bash's builtin regex:
if [[ $1 =~ ^[[:digit:]]+$ ]]; then
...
fi
Even without bash's builtin regex, there is no need for the test command ( [ ), or echo:
if grep -q -E '^[[:digit:]]+$' <<< "$1"; then
...
fi
If this must also work on shells other than bash, then you can keep the echo:
if echo "$1" | grep -q -E '^[[:digit:]]+$'; then
...
fi
The last two work because if tests the exit status of a command. The grep command returns non-zero if a match is not found.
I'm not entirely certain what you mean, but here are two things you can try:
If you're trying to print the entire line as-is (including the $1), use single-quotes to tell echo to not interpret anything:
$ echo 'if [ "` echo $1 | egrep ^[[:digit:]]+$`" = "" ]'
if [ "` echo $1 | egrep ^[[:digit:]]+$`" = "" ]
If you're trying to print the entire line but substitute in the current value for $1:
$ echo "if [ \"\` echo $1 | egrep ^[[:digit:]]+\$\`\" = \"\" ]"
if [ "` echo <<some value>> | egrep ^[[:digit:]]+$`" = "" ]
If you're trying to substitute the entire portion of the command that's in backticks (evaluated using the current value of $1), it's probably best to use an intermediate variable:
temp=$(echo $1 | egrep ^[[:digit:]]+$)
echo "if [ \"$temp\" = \"\" ]"
put a back slash before every offending character: echo if [ \"` echo $1 \| egrep ^[[:digit:]]+$`\" = \"\" ]
echo "\$1" should do exactly what you said it did.
To echo the CONTENTS of '1' then echo $1 (without the backslash).
When using variables in bash scripts, it's often good practice to double quote them (echo "$1", func_name "$1", etc) or to escape them ( echo "${1}" ).
As to the first part, are you wanting to echo the entire 'if' statement to the file? That's what it looks like. If not, then you should do this:
if [ conditions ]; then echo "$1" >> $filename
Related
I am taking baby steps at learning bash and I am developing a piece of code which takes an input and checks if it contains any spaces. The idea is that the variable should NOT contain any spaces and the code should consequently echo a suitable message.
Try this:
#!/bin/bash
if [[ $1 = *[[:space:]]* ]]
then
echo "space exist"
fi
You can use grep, like this:
echo " foo" | grep '\s' -c
# 1
echo "foo" | grep '\s' -c
# 0
Or you may use something like this:
s=' foo'
if [[ $s =~ " " ]]; then
echo 'contains space'
else
echo 'ok'
fi
You can test simple glob patterns in portable shell by using case, without needing any external programs or Bash extensions (that's a good thing, because then your scripts are useful to more people).
#!/bin/sh
case "$1" in
*' '*)
printf 'Invalid argument %s (contains space)\n' "$1" >&2
exit 1
;;
esac
You might want to include other whitespace characters in your check - in which case, use *[[:space:]]* as the pattern instead of *' '*.
You can use wc -w command to check if there are any words. If the result of this output is a number greater than 1, then it means that there are more than 1 words in the input. Here's an example:
#!/bin/bash
read var1
var2=`echo $var1 | wc -w`
if [ $var2 -gt 1 ]
then
echo "Spaces"
else
echo "No spaces"
fi
Note: there is a | (pipe symbol) which means that the result of echo $var1 will be given as input to wc -w via the pipe.
Here is the link where I tested the above code: https://ideone.com/aKJdyN
You could use parameter expansion to remove everything that isn't a space and see if what's left is the empty string or not:
var1='has space'
var2='nospace'
for var in "$var1" "$var2"; do
if [[ ${var//[^[:space:]]} ]]; then
echo "'$var' contains a space"
fi
done
The key is [[ ${var//[^[:space:]]} ]]:
With ${var//[^[:space:]]}, everything that isn't a space is removed from the expansion of $var.
[[ string ]] has a non-zero exit status if string is empty. It's a shorthand for the equivalent [[ -n string ]].
We could also quote the expansion of ${var//[^[:space:]]}, but [[ ... ]] takes care of the quoting for us.
I made a script to check tnsping but the if statement does not working properly. The following is the script:
ping=$(tnsping oracle1 |grep OK| awk -F" " '{print $1 }')
if [ -n $ping ]
then
echo "OK"
else
echo "NOT OK"
fi
If a execute change oracle for a non-existing oracle server I also receive "OK".
-n = The length of STRING is greater than zero
Wrap double quotes around $ping:
if [ -n "$ping" ]
then
echo "OK"
else
echo "NOT OK"
fi
Or it will undergo word splitting and globbing and resolve in the following arguments for [: '-n' and ']' when $ping is empty. which is the same as:
if [ '-n' '-n' ']'
See man test:
-n STRING
the length of STRING is nonzero
STRING
equivalent to -n STRING
-z STRING
the length of STRING is zero
And FYI you can omit the call to grep and use awk directly. And since the default Field Separator (-F) is space that can be omitted as well:
ping=$(tnsping oracle1 | awk '/OK/{print $1 }')
Neither the $ping variable nor awk are necessary, since grep can return an exit code to if:
if tnsping oracle1 | grep --quiet OK
then
echo "OK"
else
echo "NOT OK"
fi
At first I want to assure that I was looking for the answer for a few hours by now and I've read a lot similar questions but none of them solved my problem.
Straight to the point now:
I have two scripts in bash: one is "tool" that do some stuff for me and the second one is main "for user" script.
I want to pass to the tool script various patterns (like "[A-Za-z0-9]*" or "&")
And here is some code:
#!/bin/bash
SET() {
wz1=`./PREP2.sh $1 $2 '[0-9A-Za-z]\*'`
wz2=`./PREP2.sh $1 $2 '&'`
echo $wz1
echo $wz2
}
SET $1 $2
Tool script is actually working if I declare patterns inside like this:
line='[0-9A-Za-z]*'
But when I pass the same pattern with
'\*'
I can't get rid of "\" without interpreting "*" as "show all files in catalog".
I've been trying to use eval inside the tool like this:
eval echo '$3'
But it didn't work.
Full code follow.
User script:
#!/bin/bash
SET() {
#echo '[0-9A-Za-z]*'
wzor1=$(./PREP2.sh "$1" "$2" '[0-9A-Za-z]*')
wzor2=`./PREP2.sh $1 $2 '&'`
echo $wzor1
echo $wzor2
}
SET $1 $2 $4
Tool code
#!/bin/bash
PREP2() {
#echo "$3"
wzor="`./PREP.sh $1 $2 | tee linie.txt`"
#tmp="`echo $wzor | sed 's/,/,%/'`"
#echo $tmp;
./ZAMIEN_WSZYSTKIE_WYSTAPIENIA.sh linie.txt , #%
#tmp="`echo $wzor | tr '#' '\n x' | tee linie.txt`"
tmp="`tr '#' '\n x' < linie.txt | tee linie.txt`"
llini=`echo "$tmp" | wc -l`
#echo liczba lini $llini
i=1
wzor=""
while [ $i -le $llini ];
do
linia="`eval sed -n -e $i\p linie.txt | cut -d '%' -f2`"
if [ -z "$linia" ];then
#linia='[0-9A-Za-z]*'
linia=`eval '$3'`
#echo $linia
fi
if [ $i -ne 1 ];then
#echo "kolejna wartosc"
wzor=$wzor\,$linia
else
#echo "pierwsza wartosc"
wzor=$linia
fi
i=`expr $i + 1`
done
echo $wzor
#wynik="`grep -v "$wzor" $1`"
#echo "$wynik" > $1
#echo $nowy_wpis >> $1
}
eval echo "$3"
#PREP2 $1 $2 $3
And just to clear things up I don't actually go into procedure because I know it is working weird because of the arguments I put into it.
Quotes, quotes, quotes and more quotes. And prefer $() to backticks, that saves some quoting problems.
#!/bin/bash
SET() {
wz1=$(./PREP2.sh "$1" "$2" '[0-9A-Za-z]*')
wz2=$(./PREP2.sh "$1" "$2" '&')
echo "$wz1"
echo "$wz2"
}
SET "$1" "$2"
(BTW: it's unusual to have function names all uppercase. That's usually for environment variables.)
I want to write a script that take 1 command line argument( a directory) and then prompt for 2 number, it will then print out any file(each in a different line) that has the size between that 2 number, this is my script
echo -n "Enter the first number: "
read a
echo -n "Enter the second, bigger number: "
read b
if
[ $b -lt $a ]
then
echo 'The first number must be smaller'
else
echo The files in $1 that are between $a and $b bytes are the following
echo
for var in 'ls $1'
do
if
[ -f $var ]
then
size='ls -l $var | '{ print $5 }''
if
[ $size -le $b && $size -ge $a ]
then
echo $var is $size bytes
fi
fi
done
fi
The problem is after I enter the numbers, it will print out "The files..." and then nothing else. Also, I use Vi to edit it,but the color of last three lines is not quite right(the color should match the first "fi" but it not). Can anyone show me what was wrong? Thank you.
Your immediate problem is that you used single quotes where you wanted command substitution. However, this is the wrong way to iterate over files. You should use pattern matching instead. Your for loop should read
for var in $1/*
do
if [ -f "$var" ]
then
# Check 'man stat' for the correct format string on your system
size=$(stat +%s "$var")
if [ $size -le $b ] && [ $size -ge $a ]
then
echo $var is $size bytes
fi
fi
done
There are a couple of problems here, but the one that I think has you stuck is that the single-quote character (') is used in a couple of places where the backtick character (`) should be used. This is a subtle typographical distinction, so sometimes people that haven't encountered it before don't pick up on the distinction. On my keyboard, you get a backtick character by hitting the key just to the left of the number 1, it is paired with the tilde (~), but your keyboard may be different.
The backtick allows you to assign the output of a command to a variable, for example:
my_variable=`ls - l` # <- uses backtick, assigns output of 'ls -l' command to $my_variable
#As opposed to:
my_variable='ls -l' # <- uses single-quote, makes $my_variable equal to the text "ls -l"
Note, this will also fix your vi issue if you replace the correct single-quotes w/backticks.
As stated by others, use a shebang and use backticks for your commands. Other things that were wrong, ls -l $var | '{ print $5 }' should be ls -l "$1$var" | awk '{ print $5 }' (awk command was missing), and when testing the files you should use the full path to the file like [ -f "$1$var" ] since the user may not be in the same directory as the path they provide as an argument to the script. Another problem is [ $size -le $b && $size -ge $a ]. You can't use the && operator that way, instead use [ $size -le $b ] && [ $size -ge $a ].
These are all the changes I made to your code. Hope it works for you.
echo -n "Enter the first number: "
read a
echo -n "Enter the second, bigger number: "
read b
if [ $b -lt $a ]
then
echo 'The first number must be smaller'
else
echo The files in "$1" that are between "$a" and "$b" bytes are the following
echo
for var in `ls "$1"`
do
if [ -f $1$var ]
then
size=`ls -l "$1$var" | awk '{ print $5 }'`
if [ $size -le $b ] && [ $size -ge $a ]
then
echo "$var" is "$size" bytes
fi
fi
done
fi
I want to check if a file contains a specific string or not in bash. I used this script, but it doesn't work:
if [[ 'grep 'SomeString' $File' ]];then
# Some Actions
fi
What's wrong in my code?
if grep -q SomeString "$File"; then
Some Actions # SomeString was found
fi
You don't need [[ ]] here. Just run the command directly. Add -q option when you don't need the string displayed when it was found.
The grep command returns 0 or 1 in the exit code depending on
the result of search. 0 if something was found; 1 otherwise.
$ echo hello | grep hi ; echo $?
1
$ echo hello | grep he ; echo $?
hello
0
$ echo hello | grep -q he ; echo $?
0
You can specify commands as an condition of if. If the command returns 0 in its exitcode that means that the condition is true; otherwise false.
$ if /bin/true; then echo that is true; fi
that is true
$ if /bin/false; then echo that is true; fi
$
As you can see you run here the programs directly. No additional [] or [[]].
In case if you want to check whether file does not contain a specific string, you can do it as follows.
if ! grep -q SomeString "$File"; then
Some Actions # SomeString was not found
fi
In addition to other answers, which told you how to do what you wanted, I try to explain what was wrong (which is what you wanted.
In Bash, if is to be followed with a command. If the exit code of this command is equal to 0, then the then part is executed, else the else part if any is executed.
You can do that with any command as explained in other answers: if /bin/true; then ...; fi
[[ is an internal bash command dedicated to some tests, like file existence, variable comparisons. Similarly [ is an external command (it is located typically in /usr/bin/[) that performs roughly the same tests but needs ] as a final argument, which is why ] must be padded with a space on the left, which is not the case with ]].
Here you needn't [[ nor [.
Another thing is the way you quote things. In bash, there is only one case where pairs of quotes do nest, it is "$(command "argument")". But in 'grep 'SomeString' $File' you have only one word, because 'grep ' is a quoted unit, which is concatenated with SomeString and then again concatenated with ' $File'. The variable $File is not even replaced with its value because of the use of single quotes. The proper way to do that is grep 'SomeString' "$File".
Shortest (correct) version:
grep -q "something" file; [ $? -eq 0 ] && echo "yes" || echo "no"
can be also written as
grep -q "something" file; test $? -eq 0 && echo "yes" || echo "no"
but you dont need to explicitly test it in this case, so the same with:
grep -q "something" file && echo "yes" || echo "no"
##To check for a particular string in a file
cd PATH_TO_YOUR_DIRECTORY #Changing directory to your working directory
File=YOUR_FILENAME
if grep -q STRING_YOU_ARE_CHECKING_FOR "$File"; ##note the space after the string you are searching for
then
echo "Hooray!!It's available"
else
echo "Oops!!Not available"
fi
grep -q [PATTERN] [FILE] && echo $?
The exit status is 0 (true) if the pattern was found; otherwise blankstring.
if grep -q [string] [filename]
then
[whatever action]
fi
Example
if grep -q 'my cat is in a tree' /tmp/cat.txt
then
mkdir cat
fi
In case you want to checkif the string matches the whole line and if it is a fixed string, You can do it this way
grep -Fxq [String] [filePath]
example
searchString="Hello World"
file="./test.log"
if grep -Fxq "$searchString" $file
then
echo "String found in $file"
else
echo "String not found in $file"
fi
From the man file:
-F, --fixed-strings
Interpret PATTERN as a list of fixed strings, separated by newlines, any of
which is to be matched.
(-F is specified by POSIX.)
-x, --line-regexp
Select only those matches that exactly match the whole line. (-x is specified by
POSIX.)
-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero
status if any match is
found, even if an error was detected. Also see the -s or --no-messages
option. (-q is specified by
POSIX.)
Try this:
if [[ $(grep "SomeString" $File) ]] ; then
echo "Found"
else
echo "Not Found"
fi
I done this, seems to work fine
if grep $SearchTerm $FileToSearch; then
echo "$SearchTerm found OK"
else
echo "$SearchTerm not found"
fi
grep -q "something" file
[[ !? -eq 0 ]] && echo "yes" || echo "no"