Issue with all conditions (configuration profiles) being checked - bash

Ok, so now I have it setup like this but still it is giving me a ; exit;
logout
[Process completed]
when run through the terminal I know that there are configuration profiles that are not on my computer that should make the script continue or rather to keep looping. What is this not happening?
Thanks in advance....!
Here is what i have so far:
#!/bin/bash
profilesInstalled=`profiles -P|awk '/attribute/ {print $4}'`
while read line ; do
if [ "$line" = "F2CC78D2-A63F-45CB-AE7D-BF2221D41218" ];then
echo "AD Binding is present"
elif [ "$line" = "1C94DAD1-5FC7-46CE-9E09-576841C15093" ];then
echo "Energy Saver is present"
elif [ "$line" = "A0E5B977-F0AF-44C9-8001-DA0511B702B8" ];then
echo "Finder is present"
elif [ "$line" = "5E9DE5BF-34E4-4A7F-AA29-461FB0631943" ];then
echo "FV2 Redirect is present"
elif [ "$line" = "9AE91C88-D1B2-4227-9E95-80F492DCAA11" ];then
echo "Login Window/Security and Privacy is present"
elif [ "$line" = "00000000-0000-0000-A000-4A414D460003" ];then
echo "MDM Profile is present"
elif [ "$line" = "5E85BBF0-3483-4C80-A1FC-70AF20F82E7C" ];then
echo "Restrictions is present"
elif [ "$line" = "E433D546-5502-4C3F-9E5F-4732ED1F0032" ];then
echo "SAC SUBCA-01 is present"
elif [ "$line" = "5C2AE16B-D4E9-4D15-B190-3CD7B28779E8" ];then
echo "SAC SUBCA-02 is present"
elif [ "$line" = "2C620A13-DF1E-4F6A-A32B-9FA3149F8A56" ];then
echo "SAC-CA-01 is present"
elif [ "$line" = "3B44AE14-E0CE-4621-BACF-1A9C3BA4A459" ];then
echo "Screensaver is present"
elif [ "$line" = "396A9D84-A9CA-4575-8D09-C9F054B76AF7" ];then
echo "Spotlight is present"
elif [ "$line" = "E0138F02-9A15-47BD-8CA5-7D1D0985A1A6" ];then
echo "Workday Corp is present"
fi
exit 0
done <<<"$profilesInstalled"

You need a space around the = in those tests. That first test will always pass as written.
You should also quote the "$line" variable expansion.
Unless you use $profilesInstalled somewhere else you don't need that variable at all and can just pipe the profiles pipeline to the while loop directly.
You can also replace grep in that pipeline with awk '/attribute/ {print $4}'.

Some "meta" remarks first:
Please don't change your original question substantially, as that can invalidate existing answers (such as Etan Reisner's helpful answer)
Instead, add later changes to the original question and mark the changes as such.
If a different (follow-up) question arises, ask it as a separate, new question.
Please learn how to format your code properly - it was done for you, and you managed to destroy that formatting again with your later edits.
Please read about how to provide an MCVE (a Minimal, Complete, and Verifiable Example).
Not doing these things:
makes it far less likely that you'll get the help you need.
makes your question and its answers less valuable to future readers.
Here's a cleaned-up version of your code:
# Helper function to determine a string's element index in an array.
# SYNOPSIS
# indexOf needle "${haystack[#]}"
# *Via stdout*, returns the zero-based index of a string element in an array of strings or -1, if not found.
# The *return code* indicates if the element was found or not.
indexOf() {
local e ndx=-1
for e in "${#:2}"; do (( ++ndx )); [[ "$e" == "$1" ]] && echo $ndx && return 0; done
echo '-1'; return 1
}
# Define array of profile IDs, and parallel ID of profile names.
# Note: in bash 4+, this could be handled more elegantly with a single
# associative array.
profileIds=( F2CC78D2-A63F-45CB-AE7D-BF2221D41218 1C94DAD1-5FC7-46CE-9E09-576841C15093
A0E5B977-F0AF-44C9-8001-DA0511B702B8 5E9DE5BF-34E4-4A7F-AA29-461FB0631943
9AE91C88-D1B2-4227-9E95-80F492DCAA11 00000000-0000-0000-A000-4A414D460003
5E85BBF0-3483-4C80-A1FC-70AF20F82E7C E433D546-5502-4C3F-9E5F-4732ED1F0032
5C2AE16B-D4E9-4D15-B190-3CD7B28779E8 2C620A13-DF1E-4F6A-A32B-9FA3149F8A56
3B44AE14-E0CE-4621-BACF-1A9C3BA4A459 396A9D84-A9CA-4575-8D09-C9F054B76AF7
E0138F02-9A15-47BD-8CA5-7D1D0985A1A6 )
profileNames=( "AD Binding" "Energy Saver"
"Finder" "FV2 Redirect"
"Login Window/Security and Privacy" "MDM Profile"
"Restrictions" "SAC SUBCA-01"
"SAC SUBCA-02" "SAC-CA-01"
"Screensaver" "Spotlight"
"Workday Corp" )
# Feeding the list of installed profile IDs via a process
# substitution (<(...)), loop over them and print their
# respective names.
while read -r line ; do
# Find the line in the array of profile IDs and
# print the corresponding name.
if ndx=$(indexOf "$line" "${profileIds[#]}"); then
echo "${profileNames[ndx]} is present"
else
echo "WARNING: Unknown profile: $line" >&2
fi
done < <(profiles -P | awk '/attribute/ {print $4}')
As for why your code didn't loop:
You have an unconditional exit 0 statement in your loop, which means that the loop is always exited after the 1st line.
Due to using <<< to feed the list of profiles, you always get at least 1 line of input, because <<< appends a trailing newline to its input. If the input is empty, you'll get one iteration with an empty line.
As for this message:
; exit;
logout
[Process completed]
It tells me two things:
You're on OSX, and you ran the script from Finder.
The script produced no output (if there had been output, it would have printed between the exit; and logout lines).
When you run a script from Finder, the shell that is used to run the script exits after the script has run - and whether its Terminal window stays open or not depends on your Terminal preferences - in your case, the window stays open, but since the shell has exited, you can't interact with it anymore.
Either way, your particular script should yield the same output, whether it is run from Terminal directly, or via Finder.

Related

Shell script with absolute path and control errors

I was doing this little script in which the first argument must be a path to an existing directory and the second any other thing.
Each object in the path indicated in the first argument must be renamed so that the new
name is the original that was added as a prefix to the character string passed as the second argument. Example, for the string "hello", the object OBJECT1 is renamed hello.OBJECT1 and so on
Additionally, if an object with the new name is already present, a message is shown by a standard error output and the operation is not carried out continuing with the next object.
I have the following done:
#! /bin/bash
if [ "$#" != 2 ]; then
exit 1
else
echo "$2"
if [ -d "$1" ]; then
echo "directory"
for i in $(ls "$1")
do
for j in $(ls "$1")
do
echo "$i"
if [ "$j" = "$2"."$i" ]; then
exit 1
else
mv -v "$i" "$2"."$i"
echo "$2"."$i"
fi
done
done
else
echo "no"
fi
fi
I am having problems if I run the script from another file other than the one I want to do it, for example if I am in /home/pp and I want the changes to be made in /home/pp/rr, since that is the only way It does in the current.
I tried to change the ls to catch the whole route with
ls -R | sed "s;^;pwd;" but the route catches me badly.
Using find you can't because it puts me in front of the path and doesn't leave the file
Then another question, to verify that that object that is going to create new is not inside, when doing it with two for I get bash errors for all files and not just for coincidences
I'm starting with this scripting, so it has to be a very simple solution thing
An obvious answer to your question would be to put a cd "$2 in the script to make it work. However, there are some opportunities in this script for improvement.
#! /bin/bash
if [ "$#" != 2 ]; then
You might put an error message here, for example, echo "Usage: $0 dir prefix" or even a more elaborate help text.
exit 1
else
echo $2
Please quote, as in echo "$2".
if [ -d $1 ]; then
Here, the quotes are important. Suppose that your directory name has a space in it; then this if would fail with bash: [: a: binary operator expected. So, put quotes around the $1: if [ -d "$1" ]; then
echo "directory"
This is where you could insert the cd "$1".
for i in $(ls $1)
do
It is almost always a bad idea to parse the output of ls. Once again, this for-loop will fail if a file name has a space in it. A possible improvement would be for i in "$1"/* ; do.
for j in $(ls $1)
do
echo $i
if [ $j = $2.$i ]; then
exit 1
else
The logic of this section seems to be: if a file with the prefix exists, then exit instead of overwriting. It is always a good idea to tell why the script fails; an echo before the exit 1 will be helpful.
The question is why you use the second loop? a simple if [ -f "$2.$i ] ; then would do the same, but without the second loop. And it will therefore be faster.
mv -v $i $2.$i
echo $2.$i
Once again: use quotes!
fi
done
done
else
echo "no"
fi
fi
So, with all the remarks, you should be able to improve your script. As tripleee said in his comment, running shellcheck would have provided you with most of the comment above. But he also mentioned basename, which would be useful here.
With all that, this is how I would do it. Some changes you will probably only appreciate in a few months time when you need some changes to the script and try to remember what the logic was that you had in the past.
#!/bin/bash
if [ "$#" != 2 ]; then
echo "Usage: $0 directory prefix" >&2
echo "Put a prefix to all the files in a directory." >&2
exit 1
else
directory="$1"
prefix="$2"
if [ -d "$directory" ]; then
for f in "$directory"/* ; do
base=$(basename "$f")
if [ -f "Sdirectory/$prefix.$base" ] ; then
echo "This would overwrite $prefix.$base; exiting" >&2
exit 1
else
mv -v "$directory/$base" "$directory/$prefix.$base"
fi
done
else
echo "$directory is not a directory" >&2
fi
fi

Return variable from while loop in bash

I am trying to use a while loop to repeatedly prompt for a username during user registration until a valid username has been provided (i.e. it has NOT already been claimed).
Unfortunately, I've only been coding in bash for less than 70 hours now, so I wasn't familiar with how to do this. My initial thought was to use "goto" like in Windows batch scripts if there was a problem with the username, but apparently that's not a thing in bash and loops seemed to be the recommended route. I wasn't familiar with loops in bash so I did some research until I found a good answer on SO about how to do this. This isn't the exact post (I can't find it now), but I was looking at questions like this one.
The resulting code looks like this:
echo -e "Now, choose a unique username. No special characters, please."
uniqueuser=0 # Assume a valid username has not been chosen from the get-go
while [ "$uniqueuser" == "0" ]
do
read -p "Username: " username
lusername=`echo $username | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/` #lowercase username
if [ "$lusername" == "admin" ] || [ "$lusername" == "administrator" ] || [ "$lusername" == "npstn" ] || [ "$lusername" == "phreak" ] || [ "$lusername" == "guest" ] || [ "$lusername" == "user" ] || [ "$lusername" == "sysop" ]
then
echo -e "That username is reserved. Please pick another username."
else
username=`php /home/com/encode.php "$username"`
available=`curl "https://example.com/redacted/redacted.php?key=$key&type=checkusername&username=$username" --silent`
if [ "$available" == "1" ]
then
uniqueuser=$((1)) # Username is unique and acceptable
else
echo -e "That username is taken. Please choose another one."
fi
fi
done <input.data # so that username variable persists outside of while loop
echo -e "That username is available... or was... now, it's yours!"
echo -e "On this board, we have no annoying password length or complexity requirements. That said, your password cannot be null, nor can it use the plus symbol. Choose wisely!"
When this part of the shell script is reached, I see:
Now, choose a unique username. No special characters, please.
/home/com/redacted.sh: line 4: input.data: No such file or directory
That username is available... or was... now, it's yours!
On this board, we have no annoying password length or complexity requirements. That said, your password cannot be null, nor can it use the plus symbol. Choose wisely!
The reason "input.data" is used is to get the $username variable out from the subshell and back into the main shell. However, that seems to be causing an error. How can I fix this?
You've misread the sources on which you're relying. Redirecting stdin from a file, as in:
count=0
while IFS= read -r line; do
(( ++count )) # or do something else
done < input.data
echo "$count" # will print number of lines in the file input.data
only prevents a subshell from being created when the alternative is redirecting stdin from a pipe. For example, you would indeed lose the content of variables you set in:
# DO NOT DO THIS; this is the practice the other answers were teaching how to avoid.
count=0
cat input.data | while IFS= read -r line; do
(( ++count )) # or otherwise modify data within the loop
done
echo "$count" # will print 0, because the loop was in a subshell
This change is not necessary, and not appropriate, when your input is from stdin and not from a file.
It's the cat input.data | that is a problem, for which < input.data is a replacement. If your original code had no cat input.data |, then you need not use < input.data to replace it.
Demonstrating that a while read loop can read from stdin, and retain its variables' values, without any such redirection:
count=0
prompt='Enter a string, or a blank line to stop: '
while IFS= read -r -p "$prompt" line && [[ $line ]]; do
(( ++count ))
printf 'Line %d: %s\n' "$count" "$line"
done
echo "Final counter is $count"
...keeps the same value for $count outside the loop it hand inside the loop, when a blank line is entered.

bash - setting variable value is not working [duplicate]

This question already has answers here:
A variable modified inside a while loop is not remembered
(8 answers)
Closed 5 years ago.
Problem
My bash script loops through a bunch of files and if it finds an unexpected file that contains some text, it sets an error flag and is supposed to exit the loop. The problem is that when i evaluate the error condition after the loop, the error flag isn't set properly.
I can't seem to see where the bug is.
Code
#!/bin/sh
valid=1
grep -rs -L 'bogustext' * | while read line; do
echo "Processing file '$line'"
if [ "$line" != "arc/.keep" ] && [ "$line" != "arc/prp/lxc" ] && [ "$line" != "arc/lbb/lxc" ]; then
valid=0
echo "just set it to zero - $valid"
break 2
fi
done
echo "$valid"
if [ "$valid" -eq 0 ]; then
echo "1..1"
echo "not ok $line invis malformed"
else
echo "1..1"
echo "ok"
fi
Here's the output which shows the problem / bug. As you can see, there is an extra file in the list that contains the bogus string "arc/ttp". The script sets the "valid" variable to 0 but by the time I'm ready to evaluate it to display the right status, it's still the original value.
lab-1:/var/vrior# sh test.sh
Processing file 'arc/.keep'
Processing file 'arc/prp/lxc'
Processing file 'arc/lbb/lxc'
Processing file 'arc/ttp'
just set it to zero - 0
1
1..1
ok
What I've tried so far
I'm currently googling to see if in Bash there's local variables vs. global. Not too sure, but if you see my bug, please let me know.
Pipes create subshells, so $valid inside the loop refers to a new variable, which disappears before you try and use it.
Since you've tagged bash, then you can use a process substitution instead of the pipe:
while read line; do
echo "Processing file '$line'"
if [ "$line" != "arc/.keep" ] && [ "$line" != "arc/prp/lxc" ] && [ "$line" != "arc/lbb/lxc" ]; then
valid=0
echo "just set it to zero - $valid"
break 2
fi
done < <(grep -rs -L 'bogustext' *)

How to remove contact from shell script?

I am creating a simple phonebook using unix shell scripts. I have gotten all of my functions to work except the removal of a contact after it has been created. I have tried combining grep and sed in order to accomplish this, but cannot seem to get over the hump. The removal shell i've tried is as follows.
#!/bin/sh
#removeContact.sh
echo “Remove Submenu”
echo “Please input First Name:”
read nameFirst
echo “Please input Last Name:”
read nameLast
x=$(grep -e “$nameFirst” -e “$nameLast” ContactList)
echo $x
sed '/'$x'/ d' ContactList;
echo “$nameFirst $nameLast is removed from your contacts”
exit 0
I'm not sure if I am declaring x incorrectly, or if my syntax is wrong when sed is used.
Any help would be greatly appreciated. Thank you.
#!/bin/bash
ContactList="contacts.txt"
export ContactList
exit=0
while [ $exit -ne 1 ]
do
echo "Main Menu"
echo "(a) Add a Contact"
echo "(r) Remove a Contact"
echo "(s) Search a Contact"
echo "(d) Display All Contact’s Information"
echo "(e) Exit"
echo "Your Choice?"
read choice
if [ "$choice" = "a" ]
then
./addContact.sh
elif [ "$choice" = "r" ]
then
./removeContact.sh
elif [ "$choice" = "s" ]
then
./searchContact.sh
elif [ "$choice" = "d" ]
then
./displayContact.sh
elif [ "$choice" = "e" ]
then
exit=1
else
echo "Error"
sleep 2
fi
done
exit 0
#!/bin/sh
#addContact.sh
ContactList="contacts.txt"
echo “Please input First Name:”
read nameFirst
echo “Please input Last Name:”
read nameLast
echo “Please input Phone Number:”
read number
echo “Please Input Address”
read address
echo “Please input Email:”
read email
echo $nameFirst:$nameLast:$number:$address:$email>> ContactList;
echo "A new contact is added to your book."
exit 0
sed '/'$x'/ d' ContactList
won't remove anything from the file ContactList, it will simply output the changes to standard output.
If you want to edit the file in-place, you'll need the -i flag (easy) or to make a temporary file which is then copied back over ContactList (not so easy, but needed if your sed has no in-place editing option).
In addition, since ContactList is a shell variable referencing the real file contacts.txt, you'll need to use $ContactList.
And, as a final note, since you're using the full line content to do deletion, the presence of an address like 1/15 Station St is going to royally screw up your sed command by virtue of the fact it contains the / character.
I would suggest using awk rather than sed for this task since it's much better suited to field-based data. With the record layout:
$nameFirst:$nameLast:$number:$address:$email
you could remove an entry with something like (including my patented paranoid perfect protection policy):
cp contacts.txt contacts.txt.$(date +%Y.%m.%d.%H.%M.%S_$$)
awk <contacts.txt >tmp.$$ -F: "-vF=$nameFirst" "-vL=$nameLast" '
F != $1 || L != $2 {print}'
mv tmp.$$ contacts.txt

Bash problems with string comparison

I have a problem with writing bash script. The problem is in comparison of strings. When I launch it, there's no errors. However in result, it is always changing the variable client.
So if for an example we have two lines in file
apple A
orange D
and if I give the who=A I expect to see in result apple, or if at D - orange
But no matter of what I choose A or D it is always giving me the result - orange
No matter of the strings, it always change the variable client, like ignoring the comparison. Please help.
while read line
do
IFS=" "
set -- $line
echo $2" "$who":"$1
if [[ "$2"="$who" ]]
then
echo "change"
client=$1
fi
done < $file
echo $client
So now I changed the code as in one of the comment below, but now the caparison always false therefore the variable client is always empty
while read -r line
do
#IFS=" "
#set -- $line
#echo $2" "$who":"$1
#if [[ "$2" = "$who" ]]
a="${line% *}"
l="${line#* }"
if [[ "$l" == "$who" ]]
then
echo "hi"
client="$a"
fi
done < $file
If you have data in a file with each line like apple D and you want to read the file and separate then items, the parameter expansion/substring extraction is the correct way to process the line. For example (note $who is taken from your problem statement):
while read -r line
do
fruit="${line% *}" # remove from end to space
letter="${line#* }" # remove from start to space
if [[ "$letter" == "$who" ]]
then
echo "change"
client="$fruit"
fi
done < $file
Short Example
Here is a quick example of splitting the words with parameter expansion/substring extraction:
#!/bin/bash
while read -r line
do
fruit="${line% *}"
letter="${line#* }"
echo "fruit: $fruit letter: $letter"
done
exit 0
input
$ cat dat/apple.txt
Apple A
Orange D
output
$ bash apple.sh <dat/apple.txt
fruit: Apple letter: A
fruit: Orange letter: D
Change if [[ "$2"="$who" ]] to
if [[ "$2" = "$who" ]]
spaces around =
Example (for clarification):
who=A
while read line
do
IFS=" "
set -- $line
echo $2" "$who":"$1
if [[ "$2" = "$who" ]]
then
echo "change"
client=$1
fi
done < file #this is the file I used for testing
echo $client
Output:
A A:apple
change
D A:orange
apple
For who=D:
A D:apple
D D:orange
change
orange
You do need spaces around that = operator.
However, I think you're facing yet another issue as you're trying to change the value of the client variable from inside the while loop (which executes in a subshell). I don't think that will work; see this quesion for details.

Resources