I've tried for hours to create bulk users from a text file but I cant make it work. In the text file i have the following format:
John Smith:Student
The code:
#!/bin/bash
FILE=/home/knoppix/users.txt
GECOS=$(cat $FILE | cut -d: -f1)
USRGRP=$(cat $FILE | cut -d: -f2)
groupadd -f $USRGRP
echo "type username"
read USERNM
USERPW="123456"
useradd $USERNM -p $USERPW -g $USRGRP -c "$GECOS,$USRGRP" -d $HOME/$USERNM -s $USERSH -m
It is not working, when I tried to debug the bash script I think its not reading line by line, its grabbing all the content in the fields.
I'm missing a do while or while IFS or for line in users.txt. Something like this but I'm not expert help. also should I use newusers ir just useradd.
i need something like do while read each line
> outFile
while read var1 var2 var3 var4 ; do
echo $var1 $var2 $var3 >> outFile
echo $var4 >> outFile
done < /home/knoppix/users.txt
This assumes users.txt values are separated by spaces chars and that there are 4 words per line that you want to do some processing on.
If you values are separated with something beside space chars, for example the ':' char, then you have to tell the read command what to use as in IFS (InternalFieldSep), so
savIFS=${IFS}
> outFile
while IFS=":" read var1 var2 var3 var4 ; do
echo $var1 $var2 $var3 >> outFile
echo $var4 >> outFile
done < /home/knoppix/users.txt
IFS=${savIFS}
Also,
Code that is formed like
ECOS=$(cat $FILE | cut -d: -f1)
can be reduced to
ECOS=$( cut -d: -f1 $FILE )
Also note that for each line in $FILE, you will get a value, so if there are 3 lines of text, ECOS will be ECOS="line1Val line2Val line3Val"
I hope this helps.
Related
I have been busting my head all day long without coming up with a sucessfull solution.
Setup:
We have Linux RHEL 8.3 and a file, script.sh
There is an enviroment variable set by an application with a dynamic string in it.
export PROGARM_VAR="abc10,def20,ghi30"
The delimiter is always "," and the values inside vary from 1 to 20.
Inside the script I have defined 20 variables which take the values
using "cut" command I take each value and assign it to a variable
var1=$(echo $PROGARM_VAR | cut -f1 -d,)
var2=$(echo $PROGARM_VAR | cut -f2 -d,)
var3=$(echo $PROGARM_VAR | cut -f3 -d,)
var4=$(echo $PROGARM_VAR | cut -f4 -d,)
etc
In our case we will have:
var1="abc10" var2="def20" var3="ghi30" and var4="" which is empty
The loop must take each variable, test if its not empty and execute 10 pages of code using the tested variable. When it reaches an empty variable it should break.
Could you give me a hand please?
Thank you
Just split it with a comma. There are endless possibilities. You could:
10_pages_of_code() { echo "$1"; }
IFS=, read -a -r vars <<<"abc10,def20,ghi30"
for i in "${vars[#]}"; do 10_pages_of_code "$i"; done
or:
printf "%s" "abc10,def20,ghi30" | xargs -n1 -d, bash -c 'echo 10_pages_of_code "$1"' _
A safer code could use readarray instead of read to properly handle newlines in values, but I doubt that matters for you:
IFS= readarray -d , -t vars < <(printf "%s" "abc10,def20,ghi30")
You could also read in a stream up:
while IFS= read -r -d, var || [[ -n "$var" ]]; do
10_pages_of_code "$var"
done < <(printf "%s" "abc10,def20,ghi30")
But still you could do it with cut... just actually write a loop and use an iterator.
i=0
while var=$(printf "%s\n" "$PROGARM_VAR" | cut -f"$i" -d,) && [[ -n "$var" ]]; do
10_pages_of_code "$var"
((i++))
done
or
echo "$PROGRAM_VAR" | tr , \\n | while read var; do
: something with $var
done
suppose I have a text file something.txt. written with
4062,2016-12-31
I want to send "4062" in one command and "2016-12-31" as a string in another command in a script. Can it be done with BASH scripting?
IFS="," read -r a b < file
echo "$a"
echo "$b"
Output:
4062
2016-12-31
This would work in most cases, unless you are handling a very large file.
for line $(cat yourfile.txt)
do
field1=$(echo $line | cut -f1 -d,)
field2=$(echo $line | cut -f2 -d,)
your_command_1 $field1
your_command_2 $field2
done
a=$(cat file.txt); IFS=',' list=($a) ; echo ${list[0]}; echo ${list[1]}
I want to add some users who are in this file like:
a b
c d
e f
firstname lastname always
#!/bin/bash
Lines=$(cat newusers.txt | wc -l)
first=$(cat newusers.txt | awk '{print $1}')
last=$(cat newusers.txt | awk '{print $2}')
#test
echo $Lines;
echo $first;
echo $last;
until [ -z $1]; then
useradd - m -d /home/$1 -c "$1 + $2" $1
fi
before loop it works fine but I can't add newline.
The echo shows a c e and second for lastname b d f.
I tried to add newline in but it doesn't works.
What can i use for this?
Because I guess I can't add the user because of the newline problem.
I also searched on stackoverflow to find out a way to check if the user already exists by /dev/null but which variable do i have to use for it?
It's easier to process the file line by line:
while read first last ; do
useradd -m -d /home/"$first" -c "$fist + $last" "$first"
done < newusers.txt
I do not understand what you mean to do by your code, but if you want to read the file line by line and get the values of different fields then you can use the following code snippet:
#!/bin/bash
filename="newusers.txt"
while read -r line
do
fn=$( echo "$line" |cut -d" " -f1 )
ln=$( echo "$line" |cut -d" " -f2 )
echo "$fn $ln"
done < "$filename"
Note: You cannot add users the way you want to using bash script; since you will be prompted for password which must be supplied using tty you can use expect to program it; or use system calls.
I have the following code:
names=$(ls *$1*.txt)
head -q -n 1 $names | cut -d "_" -f 2
where the first line finds and stores all names matching the command line input into a variable called names, and the second grabs the first line in each file (element of the variable names) and outputs the second part of the line based on the "_" delim.
This is all good, however I would like to prepend the filename (stored as lines in the variable names) to the output of cut. I have tried:
names=$(ls *$1*.txt)
head -q -n 1 $names | echo -n "$names" cut -d "_" -f 2
however this only prints out the filenames
I have tried
names=$(ls *$1*.txt
head -q -n 1 $names | echo -n "$names"; cut -d "_" -f 2
and again I only print out the filenames.
The desired output is:
$
filename1.txt <second character>
where there is a single whitespace between the filename and the result of cut.
Thank you.
Best approach, using awk
You can do this all in one invocation of awk:
awk -F_ 'NR==1{print FILENAME, $2; exit}' *"$1"*.txt
On the first line of the first file, this prints the filename and the value of the second column, then exits.
Pure bash solution
I would always recommend against parsing ls - instead I would use a loop:
You can avoid the use of awk to read the first line of the file by using bash built-in functionality:
for i in *"$1"*.txt; do
IFS=_ read -ra arr <"$i"
echo "$i ${arr[1]}"
break
done
Here we read the first line of the file into an array, splitting it into pieces on the _.
Maybe something like that will satisfy your need BUT THIS IS BAD CODING (see comments):
#!/bin/bash
names=$(ls *$1*.txt)
for f in $names
do
pattern=`head -q -n 1 $f | cut -d "_" -f 2`
echo "$f $pattern"
done
If I didn't misunderstand your goal, this also works.
I've always done it this way, I just found out that this is a deprecated way to do it.
#!/bin/bash
names=$(ls *"$1"*.txt)
for e in $names;
do echo $e `echo "$e" | cut -c2-2`;
done
I am not a Linux scripting expert and I have exhausted my knowledge on this matter. Here is my situation.
I have a list of states passed as a command line argument to a shell script ( e.g "AL,AK,AS,AZ,AR,CA..." ). The Shell script needs to extract each of the state code and write it to a file ( states.txt) , with each state in one line. See below
AL
AK
AS
AZ
AR
CA
..
..
How can this be achieved using a linux shell script.
Thanks in advance.
Use tr:
echo "AL,AK,AS,AZ,AR,CA" | tr ',' '\n' > states.txt
echo "AL,AK,AS,AZ,AR,CA" | awk -F, '{for (i = 1; i <= NF; i++) print $i}';
Naive solution:
echo "AL,AK,AS,AZ,AR,CA" | sed 's/,/\n/g'
I think awk is the simplest solution, but you could try using cut in a loop.
Sample script (outputs to stdout, but you can just redirect it):
#!/bin/bash
# Check for input
if (( ${#1} == 0 )); then
echo No input data supplied
exit
fi
# Initialise first input
i=$1
# While $i still contains commas
while { echo $i| grep , > /dev/null; }; do
# Get first item of $i
j=`echo $i | cut -d ',' -f '1'`
# Shift off the first item of $i
i=`echo $i | cut --complement -d ',' -f '1'`
echo $j
done
# Display the last item
echo $i
Then you can just run it as ./script.sh "AL,AK,AS,AZ,AR,CA" > states.txt (assuming you save it as script.sh in the local directory and give it execute permission)