Ubuntu bash script string contains similar words - bash

I am trying to write a bash script that will tell whether two strings are of similar value. I have produced this bash script:
#!/bin/bash
value="java.lang.NullPointerException"
if [[ "java.lang.NullPointerException" = "$value" || "java.lang.NullPointerException" == "$value"* ]]; then
echo "Match"
fi
Basically what I want to achive, is that if two strings are of equal value or a very similar either side but with matching text in the middle then echo "Match".
I have tried a number of resources but can't get this example to work. I have taken a look at:
In bash, how can I check if a string begins with some value?
How to test that a variable starts with a string in bash?
https://ubuntuforums.org/showthread.php?t=1118003
Please note these values would eventually come from a text file and so the values will be in a form of variables. I have tried different approaches, but don't seem to get it working. I just want to get this if statement working. It works for matching text but not for values either side. Value could be "java.lang.NullPointerException: Unexpected" or "Unexpected java.lang.NullPointerException".

#!/bin/bash
value="java.lang.NullPointerException" #or java.lang.NullPointerException: Unexpected
if [[ $value == *"java.lang.NullPointerException"* ]];
then
echo "Match"
fi

A simple and portable (POSIX compliant) technique for wildcard matching is to use a case statement rather than if. For your example, this would look something like
#!/bin/sh
value="java.lang.NullPointerException"
case "$value" in
*java.lang.NullPointerException*) echo Match;;
esac

Related

Conditional ZSH_THEME by terminal

I'm trying to make that when .zshrc when invoked chooses a specific theme based on which terminal amulator i'm running. For this I came up with:
current_terminal="$(ps -p$PPID -o cmd=)"
function choose_theme {
if [ $current_terminal=~'tilix' ];
then echo 'powerlevel9k/powerlevel9k';
else echo 'robbyrussell';
fi
}
ZSH_THEME="$(choose_theme)"
I don't get any error message when running and when I open on tilix it works just fine with the powerlevel9k theme, but just that, it doesn't seem to respect the condition and I don't know where might my mstake be =/
The output for the variable current_terminal in each terminal emulator i'm using are:
Tilix:
/usr/bin/tilix --gapplication-service
Default Terminal:
/usr/lib/gnome-terminal/gnome-terminal-server
So it's getting things wright, but setting up always the first option for some reason
This does not work due to two reasons:
You are using [ ... ] instead of [[ ... ]] for the check. The difference is that [[ ... ]] is part of the ZSH's syntax and [ (aka test) is a built-in command that tries to emulate the external test program. This matters because [ does not support the =~ operator, it is only available inside [[ ... ]].
The =~ (like any other operator) needs to be surrounded by white spaces. As a Unix shell ZSH tokenizes command on white spaces. In this case ZSH I would guess that ZSH only checks whether $current_terminal=~'tilix' evaluates to a non-empty string instead of comparing $current_terminal to 'tilix'. This is always the case, hence why you always get the powerlevel9k theme.
So the condition should look like this:
current_terminal="$(ps -p$PPID -o cmd=)"
function choose_theme {
if [[ $current_terminal =~ 'tilix' ]];
then echo 'powerlevel9k/powerlevel9k';
else echo 'robbyrussell';
fi
}
ZSH_THEME="$(choose_theme)"

Unexpected end of file in while loop in bash

I am trying to write a bash script that will do the following:
Take a directory or file as input (will always begin with /mnt/user/)
Search other mount points for same file or directory (will always begin with /mnt/diskx)
Return value
So, for example, the input will be "/mnt/user/my_files/file.txt". It will search if ""/mnt/disk1/my_files/file.txt" exists and will incrementally look for each disk (disk2, disk3, etc) until it finds it or disk20.
This is what I have so far:
#/user/bin/bash
var=$1
i=0
while [ -e $check_var = echo $var | sed 's:/mnt/user:/mnt/disk$i+1:']
do
final=$check_var
done
It's incomplete yes, but I am not that proficient in bash so I'm doing a little at a time. I'm sure my command won't work properly yet either but right now I am getting an "unexpected end of file" and I can't figure out why.
There are many issues here:
If this is the actual code you're getting "unexpected end of file" on, you should save the file in Unix format, not DOS format.
The shebang should be #!/usr/bin/bash or #!/bin/bash depending on your system
You have to assign check_var before running [ .. ] on it.
You have to use $(..) to expand a command
Variables like $i are not expanded in single quotes
sed can't add numbers
i is never incremented
the loop logic is inverted, it should loop until it matches and not while it matches.
You'd want to assign final after -- not in -- the loop.
Consider doing it in even smaller pieces, it's easier to debug e.g. the single statement sed 's:/mnt/user:/mnt/disk$i+1:' than your entire while loop.
Here's a more canonical way of doing it:
#!/bin/bash
var="${1#/mnt/user/}"
for file in /mnt/disk{1..20}/"$var"
do
[[ -e "$file" ]] && final="$file" && break
done
if [[ $final ]]
then
echo "It exists at $final"
else
echo "It doesn't exist anywhere"
fi

Parsing CSV Values in Bash

I am trying to write a Bash script that will read a particular csv, and move files based on the values of a column in that csv. However, when I do so it treats everything as false and does not move the files despite the fact that I know for sure it should be reading roughly one in five lines as true.
The code is as follows
#!/bin/bash
FILE=filename.csv
while IFS=, read -a csv_line;
do
EMAIL="${csv_line[1]}" #identify the filename
HASVAL="${csv_line[62]}" #should be either 1 or 0
if [ -e "$EMAIL" ]
then
echo "detected"
if [ "$HASVAL" = "1" ]
then
mv "$EMAIL" /home/targetdirectory
echo "moved"
fi
fi
done < $FILE
I cannot see what is wrong with this script. It only prints "detected", never prints "moved" and does not move the files, so I suspect it is not matching the text correctly. Is it possible that I am reading the contents of a csv wrong and its possible for not all values in a csv to be a string? Or am I doing something else wrong?
Thank you for any help you can give.
EDIT: replacing the offending if statement with
[ "$HASVAL" -eq 1 ]
gives me
detected
: integer expression expected
on every line so I'm not sure integer comparison will work either.
EDIT: As discussed below, it looks like the problem has been solved. The .csv had DOS endings, and since I was looking at the last column it wouldn't match properly, and the last column had to be trimmed of '/r' so it could actually match it to a proper string. Thanks to everybody for the assistance.
Edit: best practices suggest using double [[ ]] and double equals for your if statement. Also have you verified you are comparing String values or should you be doing an integer comparison.

unexplained string from bash loop

I have some file in the name of OBS_SURFACE1**, OBS_SURFACE101, OBS_SURFACE103. Yes, there indeed is a file named OBS_SURFACE1**, which I guess where the problem arise. I wrote a bash script which has:
for fil in ` ls OBS_DOMAIN1?? `
do
echo "appending" $fil
done
The first value of fil will be OBS_SURFACE1** OBS_SURFACE101 OBS_SURFACE103, the second OBS_SURFACE101. While I expect the first to be OBS_SURFACE1**. If there is no OBS_SURFACE1** file, there would be no problem. Why is that then?
Don't parse ls! It will only ever lead to problems. Use a glob instead:
for fil in OBS_DOMAIN1??
do
echo "appending $fil"
done
The problem that you are experiencing stems from the fact that the output of ls contains *, which are being expanded by bash. Note that I have also quoted the whole string to be echoed, which protects against word splitting inside the loop. See the links provided in the comments above for more details on that.
As pointed out in the comments (thanks Charles), you may also want to enable nullglob before your loop like this: shopt -s nullglob. This will mean that if there are no files that match the pattern, the loop will not run at all, rather than running once with $fil taking the literal value OBS_DOMAIN1??. Another option would be to check whether the file exists in within the loop, for example using:
if [[ -e "$fil" ]]; then
echo "appending $fil"
fi
or the more compact [[ -e "$fil" ]] && echo "appending $fil".
yet another way of doing this :
echo appending OBS_DOMAIN1??
this will list all files , no loop needed.

String contains in Bash that is a directory path

I am writing an SVN script that will export only changed files. In doing so I only want to export the files if they don't contain a specific file.
So, to start out I am modifying the script found here.
I found a way to check if a string contains using the functionality found here.
Now, when I try to run the following:
filename=`echo "$line" |sed "s|$repository||g"`
if [ ! -d $target_directory$filename ] && [[!"$filename" =~ *myfile* ]] ; then
fi
However I keep getting errors stating:
/home/home/myfile: "no such file or directory"
It appears that BASH is treating $filename as a literal. How do I get it so that it reads it as a string and not a path?
Thanks for your help!
You have some syntax issues (a shell script linter can weed those out):
You need a space after "[[", otherwise it'll be interpretted as a command (giving an error similar to what you posted).
You need a space after the "!", otherwise it'll be considered part of the operand.
You also need something in the then clause, but since you managed to run it, I'll assume you just left it out.
You combined two difference answers from the substring thing you posted, [[ $foo == *bar* ]] and [[ $foo =~ .*bar.* ]]. The first uses a glob, the second uses a regex. Just use [[ ! $filename == *myfile* ]]

Resources