Check if read input is available in var - bash

I try to list all Folders in /etc/nginx/html/.
I use this code:
folders=`for i in $(ls -d */ | grep -Ev "(backups)"); do echo ${i%%/}; done`
Now I get all folders with names non containing "backups".
Now I want to count the folder and save it into var. I use this code:
folders_count=( $folders )
echo ${#folders_count[#]}
It works. I get a list of all folders and I can count the folders.
Now I try to write a script that reads user input (or better, offers 1,2,3 choices, but I do not know how to do it) and install a script like Prestashop (as an example) into the folder the user has chosen if there are more than 1 folder.
Here is my code:
folders_count=( $folders )
echo ${#folders_count[#]}
echo
if [ ${#folders_count[#]} -gt 1 ]; then
echo "${info} Please choose a Website for Prestashop:" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
# for websites in $folders; do
# echo "${info} $folders" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
# echo "${info} $folders" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
# done
echo "$folders" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
#read websites_for_prestashop
read -e -i "$websites_for_prestashop" -p "Please enter your Website: " input
websites_for_prestashop="${input:-$websites_for_prestashop}"
if [ "$websites_for_prestashop" == "$folders" ]; then
echo "Website is $websites_for_prestashop"
else
echo "Website $websites_for_prestashop is not found"
fi
#echo "${info} Please choose a Website for Prestashop:" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
else
echo "nix"
fi
I dont know how I can make it work :/
Can anyone help me to fix it?
I would like to list the available folders. Then the user should be able to select in which folder he would like to install the script.
Folders:
[0] Folder 1
[1] Folder 2
[2] Folder 3
[3] Folder 4
....
Then a query will appear:
Please select an order for the installation:
The selection of the folder should then be stored in the variable read websites_for_prestashop

I do not know what your script is supposed to be doing. There are a bunch of lines commented out, the only assignment for websites_for_prestashop contains a reference to the variable itself and occurs after this variable is first used, and the script ultimately does nothing.
What I can tell you is that the way you extract filenames is not the right way to do it. Parsing the output of ls is not a good idea (see http://mywiki.wooledge.org/ParsingLs), and the way you do it will fail on any file with a name containing spaces, among other things.
This would be one way to do it:
declare -a folders=()
for f in */
do
[[ $f =~ backups ]] || folders+=("${f%/}")
done
echo "Folder count is: ${#folders[#]}"

Thank you for your help#
https://stackoverflow.com/users/2416376/olli-k
https://stackoverflow.com/users/7422249/fred
Solution is easy:
folders=`for i in $(ls -d */ | grep -Ev "(backups)"); do echo ${i%%/}; done`
echo "${info} Please choose a Website for Prestashop:" | awk '{ print strftime("[%H:%M:%S] |"), $0 }'
select websites_for_prestashop in $folders;
do
echo "You picked $websites_for_prestashop."
break
done

Related

How to add one loop arrays value to another loop

I have a script which finds all the Cert. identity on the system then I want to add one more Cert. and delete rest of Cert except which is added recently.
1st loop finds how many identity we have in the system and set array as $var1 $var2 $var3 and no. continues.
Then I add one more.
Now I want to delete 1 loop array values herein for loop. But my $DEL variable is coming as var1 var2, not the actual identity we have set in 1st loop.
#!/bin/bash
DOM=$(/usr/sbin/dsconfigad -show | grep "Active Directory Domain" | awk '{ print $5 }')
MAC=$(/usr/sbin/dsconfigad -show | grep "Computer Account" | awk '{ print $4 }' | tr -d "$")
HOST=$MAC.$DOM
CRT=$(security find-identity -v | grep $HOST | awk '{ print $2}')
set - $CRT; index=0; while [ "$1" ];
do
let index=$index+1;
eval var${index}="$1";
shift;
done
The above loop result is: + set - 02KFKDSF89SFMDFMFS7908934M90DODFSMN78345 K69SKLD04KCM62469933FA60567LLFD730957FA3 489FHDFS93MDF89UY2345905DFSKDDSKFDS9FSEF
echo $var1
echo $var2
The echo $var1 is: 02KFKDSF89SFMDFMFS7908934M90DODFSMN78345
The echo $var2 is: K69SKLD04KCM62469933FA60567LLFD730957FA3
NUMCRT=$index
echo "Number of Certificate is $NUMCRT"
echo "Add of Script part bla bla Start"
echo "ADD one more Cert"
echo "Add of Script part bla bla END"
Now I want to delete array value which I have found in the 1st loop. But $DEL value is coming var1 var2 var3 and not 02KFKDSF89SFMDFMFS7908934M90DODFSMN78345 K69SKLD04KCM62469933FA60567LLFD730957FA3 489FHDFS93MDF89UY2345905DFSKDDSKFDS9FSEF.
for i in $(seq 1 $NUMCRT);
do
let $i;
DEL="var$i"
echo "Delete number $DEL"
done
It should show echo "Delete number $DEL" in 2nd for loop value as below.
Delete number 02KFKDSF89SFMDFMFS7908934M90DODFSMN78345
Delete number K69SKLD04KCM62469933FA60567LLFD730957FA3
Delete number 489FHDFS93MDF89UY2345905DFSKDDSKFDS9FSEF
You don't need to run dsconfigad twice.
domain=''; machine='';
while IFS="=" read key val
do case "$key" in
"Active Directory Domain"*) domain=$( echo $val ) ;; # strip space
"Computer Account"*) machine=$( echo $val ) ;; # strip space
*) if [[ -n "$domain" ]] &&
[[ -n "$machine" ]]
then break
fi;;
esac
done < <( /usr/sbin/dsconfigad -show )
I can't find a good example of security find-identity -v including the verbose option, so I'm going to fake my way through this by using your command structure, though I'm still not going to use all-caps vars (don't do that).
declare -a crt=( $( security find-identity -v | grep $machine.$domain | awk '{ print $2}' ) )
Now the values are in the $crt[#] array, numerically indexed.
If you know the index of the one you want to remove,
unset "crt[$num]"
This does leave a hole in your array...
Alternately, use the values themselves as the keys, and you won't have to track the indexes and leave holes in your array.
declare -A crt=()
while read one
do crt[$one]=1
done < <( security find-identity -v | grep $HOST | awk '{ print $2}' ) )
Now you can remove it with
unset "crt[$val]" # assuming $val is the key
or walk through them with
for val in "${!crt[#]}"
do : something with the key...
done
Useful?
As always, folks please check me. I don't have either of these tools installed. Working blind and likely screwing something up. :)

Would it be possible to print the file used to redirect STDERR?

Would it be possible to print the filename used to redirect STDERR, given the sample command below:
command.sh 2>file.err
Code in command.sh:
#!/bin/sh
ls -l non_existing_file.txt
echo "STDERR file is: $stderrFilename" # variable should print file.err
It's a little risky, but you could try parsing AIX's procfiles output. It involves capturing the major and minor numbers of the stderr device, along with the inode number, then looking for the corresponding device, its mountpoint, and then using find to look for the file with the given inode number:
#!/bin/sh
dev=$(procfiles $$ | awk '$1 == "2:" { print substr($4, 5) }')
inode=$(procfiles $$ | awk '$1 == "2:" { print substr($5, 5) }')
major=${dev%%,*}
minor=${dev##*,}
if [ "$major}" -eq 0 ]
then
echo I give up, the major number is zero
exit 1
fi
for file in /dev/*
do
[ -b "$file" ] || continue
if istat "$file" | grep -q "^Major Device ${major}.*Minor Device ${minor}$"
then
break
fi
done
fs=$(mount | awk '$1 == "'"${file}"'" { print $2 }')
stderrFilename=$(find "$fs" -inum "$inode")
I made a solution using history. Not sure if there is an easier way to do this ( or a proper one).
#!/bin/sh
stderrfname=`history | tail -1 | awk '{ print $3 }' | sed "s/.*>//"`
echo "STDERR file is: $stderrfname"

Print all users from one, selected group (GID) from /etc/passwd

I'm new here and I'm trying to learn some Bash. I need to write a script that will print all of users from etc/passwd in seperated lines from one, selected group defined as a $1 parameter.
When group does not exist, the proper message is displayed. Same for wrongly entered numbers. I manage to do this, which do all the job with messages, but I just can't find the way to write users from one group.
Example:
myscript.sh 1000
Output:
User1
User2
User3
Here's the bash file:
#!/bin/bash
awk -F':' '{ print $3 }' /etc/passwd | sort > list.txt
re='^[0-9]+$'
if grep -Fxq "$1" list.txt
then
**echo "don't know what to do here"**
else
if ! [[ $1 =~ $re ]] ; then
echo "Wrong number"
else
echo "Group does not exist"
fi
fi

Bash script read specifc value from files of an entire folder

I have a problem creating a script that reads specific value from all the files of an entire folder
I have a number of email files in a directory and I need to extract from each file, 2 specific values.
After that I have to put them into a new file that looks like that:
--------------
To: value1
value2
--------------
This is what I want to do, but I don't know how to create the script:
# I am putting the name of the files into a temp file
`ls -l | awk '{print $9 }' >tmpfile`
# use for the name of a file
`date=`date +"%T"
# The first specific value from file (phone number)
var1=`cat tmpfile | grep "To: 0" | awk '{print $2 }' | cut -b -10 `
# The second specific value from file(subject)
var2=cat file | grep Subject | awk '{print $2$3$4$5$6$7$8$9$10 }'
# Put the first value in a new file on the first row
echo "To: 4"$var1"" > sms-$date
# Put the second value in the same file on the second row
echo ""$var2"" >>sms-$date
.......
and do the same for every file in the directory
I tried using while and for functions but I couldn't finalize the script
Thank You
I've made a few changes to your script, hopefully they will be useful to you:
#!/bin/bash
for file in *; do
var1=$(awk '/To: 0/ {print substr($2,0,10)}' "$file")
var2=$(awk '/Subject/ {for (i=2; i<=10; ++i) s=s$i; print s}' "$file")
outfile="sms-"$(date +"%T")
i=0
while [ -f "$outfile" ]; do outfile="sms-$date-"$((i++)); done
echo "To: 4$var1" > "$outfile"
echo "$var2" >> "$outfile"
done
The for loop just goes through every file in the folder that you run the script from.
I have added added an additional suffix $i to the end of the file name. If no file with the same date already exists, then the file will be created without the suffix. Otherwise the value of $i will keep increasing until there is no file with the same name.
I'm using $( ) rather than backticks, this is just a personal preference but it can be clearer in my opinion, especially when there are other quotes about.
There's not usually any need to pipe the output of grep to awk. You can do the search in awk using the / / syntax.
I have removed the cut -b -10 and replaced it with substr($2, 0, 10), which prints the first 10 characters from column 2.
It's not much shorter but I used a loop rather than the $2$3..., I think it looks a bit neater.
There's no need for all the extra " in the two output lines.
I sugest to try the following:
#!/bin/sh
RESULT_FILE=sms-`date +"%T"`
DIR=.
fgrep -l 'To: 0' "$DIR" | while read FILE; do
var1=`fgrep 'To: 0' "$FILE" | awk '{print $2 }' | cut -b -10`
var2=`fgrep 'Subject' "$FILE" | awk '{print $2$3$4$5$6$7$8$9$10 }'`
echo "To: 4$var1" >>"$RESULT_FIL"
echo "$var2" >>"$RESULT_FIL"
done

Check if a particular string is in a file bash

I want to write a script to check for duplicates
For example: I have a text file with information in the format of /etc/passwd
alice:x:1008:555:William Williams:/home/bill:/bin/bash
bob:x:1018:588:Bobs Boos:/home/bob:/bin/bash
bob:x:1019:528:Robt Ross:/home/bob:/bin/bash
james:x:1012:518:Tilly James:/home/bob:/bin/bash
I want to simply check if there are duplicate users and if there are, output the line to standard error. So in the example above since bob appears twice my output would simply generate something like:
Error duplicate user
bob:x:1018:588:Bobs Boos:/home/bob:/bin/bash
bob:x:1019:528:Robt Ross:/home/bob:/bin/bash
Right now I have a while loop that reads each line and stores each piece of information in a variable using awk -F that is delimited with ":". After storing my username I am not too sure on the best approach to check to see if it already exists.
Some parts of my code:
while read line; do
echo $line
user=`echo $line | awk -F : '{print $1}'`
match=`grep $user $1`($1 is the txtfile)
if [ $? -ne 0 ]; then
echo "Unique user"
else
echo "Not unique user"
then somehow grep those lines and output it
fi
done
The matching does not produce the right results
Suggestions?
instead of re-inventing the wheel, use the following tools:
cut to extract first field
sort and uniq to keep duplicated lines only.
cut -d : -f 1 | sort | uniq -d | while read i ; do
echo "error: duplicate user $i"
done
Sounds like a job for awk to me:
% awk -F':' '
/:/ {
count[$1] += 1
}
END {
for (user in count) {
if (count[user] > 1) {
print user " appears in the file " count[user] " times."
}
}
}
' /etc/passwd
A perl-proposal:
perl -F: -lanE 'push #{$h{$F[0]}},$_; END{for $k (keys %h){if(#{$h{$k}}>1){say "Error";say for #{$h{$k}}}}}' file

Resources