Comparing 2 lists of users in bash - bash

I have 2 variables that contains a list of users
echo $old_users
1
2
3
4
5
6
echo $new_users
1
2
3
4
I want to know which users from the old_users list were removed in the new_users list (here user 5 and 6). This is what I have written so far but I still miss something:
echo $old_users | while read line
do
if echo "$new_users"| grep "$line"
then
echo "$line user was removed"
else
echo "$line user is still there"
fi
done
Any help appreciated! Thanks

for line in $old_users
do
if echo "$new_users"| grep "$line" #[ You can use grep -w for exact match here ]
then
echo "$line user was removed"
else
echo "$line user is still there"
fi
done
Hope it will work now.

This is somewhat similar to https://superuser.com/a/135180. So using that here might be beneficial. This will take the set difference of old_users - new_users.
diff --changed-group-format='%<' --unchanged-group-format='' <(echo $old_users) <(echo $new_users)

Related

Increment Number in ZSH script

I am trying to create directories based off of the number of files I have in a directory and my approach is a loop.
I am keeping track of the number by a number variable and want to increment it as so after each even number, create a directory.
This is my code so far:
#!/bin/zsh
LOOP=$(ls 2021/*.xlsx)
totalFiles=$(ls 2021/*.xlsx | wc -l)
directoryCount=0
count=0
for FILE in ${LOOP[#]}; do
echo "BEFORE: $count"
count=$((count+1))
echo "AFTER: $count"
echo $FILE
done
echo "TOTAL FILE: $totalFiles"
echo $count
and the output I get is:
BEFORE: 0
AFTER: 1
2021/*Tanner2103.xlsx
2021/*Tanner2104.xlsx
2021/*Tanner2105.xlsx
2021/*Tanner2106.xlsx
TOTAL FILE: 4
1
I dont understand why count only increments once but the loop is obviously has more iterations than that.
So basically since there are 4 files, I want to split them up into 2 directories, Ill do the logic for that later. But for now Im just trying to get the directory code working.
Ok I feel silly. I thought that ls would come back as an iterable but its actual only return one iteration as a whole.
This is my updated code and it updating like I want.
totalFiles=$(ls 2021/*.xlsx | wc -l)
count=0
for FILE in 2021/**/*(.); do
echo "BEFORE $count"
echo "$FILE"
((count++))
echo "AFTER $count"
done
echo "TOTAL FILE: $totalFiles"
echo $count
result:
BEFORE 0
2021/*Tanner2103.xlsx
AFTER 1
BEFORE 1
2021/*Tanner2104.xlsx
AFTER 2
BEFORE 2
2021/*Tanner2105.xlsx
AFTER 3
BEFORE 3
2021/*Tanner2106.xlsx
AFTER 4
TOTAL FILE: 4
4

Difficulty in mentioning multiple calls in a single line of echo

The problem I have is with echo cannot echo e.g: "$prefix_$suffix". This is a assignment for a class in school if that changes things.
I've tried e.g "$prefix _$suffix" but that creates a space between the prefix and suffix
#!bin/bash
read -p "Username prefix: " prefix
read -p "Amount of users: " amount
read -p "Name of file to store, include extension (e.g test.txt): " filename
touch "$filename"
new="$amount"
suffix=0
state=true
while [ state=true ] ; do
#in this function i reverse the user input amount of users so it appears as user 1,2,3 (and so on) in the first line of the text file that is also user input.
if [ "$new" -ge 1 ] ; then
newpass="$(gpg --gen-random --armor 1 12)"
#reversing process, making the suffix start at 1 so user 1 gets assigned suffix 1 for the username and i decrease the "new" variable that gets set to "$amount" so the while loop isn't indefinite
new=`expr "$new" - 1`
suffix=`expr "$suffix" + 1`
echo -n "$prefix" >> "$filename"
echo -n "_$suffix" >> "$filename"
echo -n " " >> "$filename"
echo "$newpass" >> "$filename"
echo -e >> "$filename"
elif [ "$new" -eq 0 ] ; then
break
fi
done
a run of this bash results in 5 lines e.g:
re_1 UlrZW3jB5L9zt6Nf
and so on, depending how many users you choose at the input
however the next task is to create users with the username, in this example re_1 with the password: UlrZW3jB5L9zt6Nf. This is where the clunky echo stuff I've done doesn't work. I tried doing useradd -u "$prefix_$suffix" and "$prefix $suffix" , none of these work since "$prefix$suffix" is treated as one call instead of two and the "$prefix _$suffix" adds one space in between the prefix and suffix which is not acceptable.
Even if this looks very introverted to you, hence i added comments to make it understandable, help is very appreciated.
Feel free to ask question if you do not understand and want to help!
This will do what you want:
echo "${prefix}_${suffix}"

`echo " $1 % 2" | bc -l` doesn't work in the terminal or bash script but `bc` takes these arguments within `bc` [duplicate]

This question already has answers here:
bash, bc modulo does not work with -l flag
(5 answers)
How do I check whether a variable has an even numeric value?
(3 answers)
Closed 4 years ago.
I haven't been able to find anything related to this nor can my professor explain what's going on. Below is the problem description:
After quite a bit of debugging following is the bash script to print odd or even:
echo $1
odd_even=$(echo "$1 % 2" | bc -l)
echo $odd_even
if [[ $odd_even -eq 0 ]]
then
echo "even"
else
echo "odd"
fi
Following is the output:
$ bash logic_ex2.sh 3
3
0
even
This is weird because the variable odd_even contains 0 while the argument is 3.
We ran the following command to check whats wrong with the echo "3 % 2" | bc -l construction since without using that construction we could get the script working:
$ echo "3 % 2" | bc -l
0
Then we ran bc in the terminal and ran 3 % 2 which gave 1 as the proper output.
Can somebody please explain what is happening here?
Check this explanation as to bc -l calculates a % b differently from plain bc without the -l. The quick solution is to set your scale back to zero:
$ bc -l <<< "scale=0; 3 % 2"
1
But I would probably do this without using bc at all, since bash includes sufficient functionality to calculate integer remainders. If all you need is integer math, bash may be good enough on its own.
#!/usr/bin/env bash
echo "$1"
odd_even=$(($1 % 2))
echo "$odd_even"
if [[ $odd_even -eq 0 ]]; then
echo "even"
else
echo "odd"
fi
My results:
$ bash remtest.sh 3
3
1
odd
$ bash remtest.sh 4
4
0
even
another option:
#!/bin/bash
var=$1
if [[ $((var % 2)) -eq 0 ]];
then echo "$var is even";
else echo "$var is odd";
fi

Nested while loop not working in Bash

Beginner here so bear with me. I am trying to compare homework submissions from a solution file and a student submission file. The contents of each file have three problems, one per line:
problem 1 code
problem 2 code
problem 3 code
I want to compare each line in the solution with the corresponding line in the students submission. I am using a for loop to run through each student file and a nested while loop to run through each line of the solution file and student file. For some reason the script is completely ignoring the while loop. I have put echoes between each line to see where the problem is(the echo $solution and echo $submission is just to check to see if the path is correct):
for submission in /home/myfolder/submissions/*
do
echo 1
solution=$(echo /home/myfolder/hwsolution/*)
echo 2
echo $solution
echo $submission
while read sans <&1 && read sol <&2
do
echo 3
echo Student awnser is: $sans
echo Solution is: $sol
echo 4
done 1<$(echo $submission) 2<$(echo $(echo $solution))
echo 5
done
When I run it I get:
1
2
/home/myfolder/hwsolution/solution
/home/myfolder/submissions/student1
5
1
2
/home/myfolder/hwsolution/solution
/home/myfolder/submissions/student2
5
1
2
/home/myfolder/hwsolution/solution
/home/myfolder/submissions/student3
5
It's not ignoring the while loop -- you're redirecting the file descriptors used for stdout and stderr, so echo can't write to the console within it.
for submission in /home/myfolder/submissions/*; do
solutions=( /home/myfolder/hwsolution/* )
if (( ${#solutions[#]} == 1 )) && [[ -e ${solutions[0]} ]]; then
solution=${solutions[0]}
else
echo "Multiple solution files found; don't know which to use" >&2
printf ' - %q\n' "${solutions[#]}" >&2
exit
fi
while read sans <&3 && read sol <&4; do
echo "Student awnser is: $sans"
echo "Solution is: $sol"
done 3<"$submission" 4<"$solution"
done
The most immediate change is that we're redirecting FD3 and FD4, not FD1 and FD2.

Validating multiple inputs procured through read command

I am trying to validate multiple inputs separated by spaces(two disk names in the below case) with a shell script. But, I am un-successful in doing so. Can someone help me?
read DISK
if [ "${1}" = "" ] || [ "${2}" = "" ]
then
printf "The Disk pairs cannot be left blank. Exiting script!!!"
exit 1
else
TMP=$DISK
printf "The disks entered are $TMP"
fi
For ksh93, you can use
read -A disks
if [[ ${#disks[#]} -ne 2 ]]; then
print -u2 "You need to enter 2 disks"
exit 1
else
print "You entered: ${disks[*]}"
fi
For ksh88, use the positional parameters
read disks
set -- $disks
if [[ $# -ne 2 ]]; then
print -u2 "You need to enter 2 disks"
exit 1
else
print "You entered: $disks"
fi
The variables ${1} and ${2} are the commandline parameters and are unrelated to the last read command. There are different ways to use the DISK variable.
Once you have the DISK variable read, I would have chosen for a solution like
echo "${DISK}" | while read disk1 disk2 otherfields; do
echo "disk1=${disk1}, disk2=${disk2}"
done
# or better
disk1="${DISK% *}"; echo "${disk1}"
disk2="${DISK#* }"; echo "${disk2}"
# or worse
disk1=$(echo "${DISK}" | cut -d" " -f1)
disk2=$(echo "${DISK}" | cut -d" " -f2)
When you already know you want to split the fields, you can change your first read command. Replace read DISK with
read disk1 disk2 remaining_input

Resources