This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Linux Script Extract Information From Excel To Create Users
Need to create users from excel spread sheet, getting a few errors in my script on lines 8 and 13
Line 8 Unexpected EOF while looking for matching `''
Line 13 Syntax error unexpected end of file
#!bin/bash
echo $(pwd)/employeesdata.xls
Path=$($pwd)/employeesdata.xls
read Path
if [ -e $Path ];
then
Username= [ grep $(Username) $Path | cut -f1 -d `]'
Password= [ grep $(Password) $Path | cut -f2 -d `]'
useradd -- b $Username
echo $Password | /usr/bin/passwd --stdin $Username
fi
exit
Excel file has this and other information
Name (field1) EmployeeID (field2) Phone Address
Joe Blow 22500033 156-454-3322 101 main
I think you'd have to refactor a few things:
#!bin/bash
echo $(pwd)/employeesdata.xls
Path="$(pwd)/employeesdata.xls"
read Path
if [ -e "$Path" ]; then
Username=$(grep "$Username" "$Path" | cut -f1 -d ' ')
Password=$(grep "$Password" "$Path" | cut -f2 -d ' ')
useradd -- b $Username
echo "$Password" | /usr/bin/passwd --stdin "$Username"
fi
exit
A few notes:
Quote the value you are assigning to a variable (sometimes this is not necessary, but for starting out it helps to avoid some problems)
Quote the usage of a variable, unless you know what you're doing. Without quoting it explicitly, the variable can generate various parameters to commands/functions.
$(cmd) executes the command cmd and replaces its occurrence with the output of the command.
$var or ${var} replaces itself with the contents of variable named var
"quoting $a", supposing the variable a contains string as its contents, generates the string quoting string.
'quoting $a', independent of the variable a, generates the string quoting $a.
As confusing as it can be for newcomers, [ is actually an "alias" for the test command, which can be used to compare strings, integers, and do some basic tests like checking the permissions or the existence of a file. ] is actually just a syntax requirement just to inform the command that its parameters have ended (when called .
I assumed your delimiter is a space, but I could be wrong.
Hope this helps a little =)
Related
I am trying to make this interactive script take inputs in a non-interactive way by declaring $username and $password variables in bash env and pass them as inputs to the script. By running ./input.sh <<< "$username"
#!bin/bash
read username
read password
echo "The Current User Name is $username"
echo " The Password is $password"
is there a way to pass both the variables as input? Because with what I have tried it only takes one input this way.
So, staying as close as possible as your initial try (but I doubt that is the best solution for any real problem), what you are asking is "how I can pass 2 lines with here-string".
A possible answer would be
./input.sh <<< "$username"$'\n'"$password"
here-strings are the construct you are using when using <<<. When you type ./input.sh <<< astring it is, sort-of, the same as if you were typing echo astring | ./input.sh: it use the string as standard input of ./input.sh. Since your reads read lines, you need 2 lines as standard input to achieve what you want. You could have done this that way: (echo "$username" ; echo "$password") | ./input.sh. Or anyway that produces 2 lines, one with $username one with $password and redirecting those 2 lines as standard input of ./input.sh
But with here-string, you can't just split in lines... Unless you introduce explicitly a carriage return (\n in c notation) in your input string. Which I do here using $'...' notations, that allows c escaping.
Edit. For fun, I include here the other solutions I wrote in comments, since you are not specially requiring here-strings.
(echo "$username" ; echo "$password") | ./input.sh
{echo "$username" ; echo "$password" ; } | ./input.sh
printf "%s\n" "$username" "$password" | ./input.sh
./input.sh < <(echo "$username" "$password")
./input.sh < <(printf "%s\n" "$username" "$password")
Plus of course solutions that changes ./input.sh
#!bin/bash
username="$1"
password="$2"
echo "The Current User Name is $username"
echo " The Password is $password"
called with ./input "$username" "$password"
Or
#!bin/bash
echo "The Current User Name is $username"
echo " The Password is $password"
called with username="$username" password="$password" ./input.sh
Easiest way would be something like that:
#!/bin/bash
echo "The Current User Name is $1"
echo "The Password is $2"
$1 represents the first given argument and $2 the second.
[user#vm ~]$ input.sh "user" "password"
Inside the quotation marks ("") put the argument you want to pass.
For more professional/robust solution check this out: Redhat: Bash Script Options/Arguments
To get this code to run properly, I created a txt file named new_user.txt with the following format (supposed to follow /etc/passwd)
doejjan:x:Doe, Jane Joe+111222:home/STUDENTS/teststu:/bin/bash
smidjoh:x:Smith, John Jay+222333:home/STUDENTS/teststu:/bin/bash
I want to try to display the command that was created to show every record on the screen, below is what I have so far:
#!/bin/bash
while read -r line || [[ -n "$line" ]]; do
username=$(echo "$line" | cut -d: -f1)
GECOS=$(echo "$line" | cut -d: -f5)
homedir=$(echo "$line" | cut -d: -f6)
echo "adduser -g '$GECOS' -d '$homedir' -s /bin/bash '$username'"
done < "$new_user.txt"
I'm getting the error in line 7 that says the following:
.txt:No such file or directory
Can you help me try to fix the error message? Thank you in advance.
From the error message, you can understand that the variable new_user must be empty. Indeed you never assign a value to this variable.
From your description, it follows that $new_user should expand to the value new_user. Say your script is called my_script. If you run it as
new_user=new_user my_script
the error will be gone. If the script is run most of the time on the file new_user.txt, you can - in your script - provide a default value for this variable:
: ${new_user:=new_user}
If you then run it as
my_script
it will pick up new_user.txt, but if you run it by
new_user=old_user my_script
it will run on old_user.txt.
BTW, I personally would prefer passing the file name to the script either via stdin or on the command line, but you have choosen to use a variable for this task, and you can do this of course, if you prefer.
I am trying to construct an if-else block wherein one of the conditions is to echo a message if, when running a grep command on a text file, the specified token can not be found.
The grep command is
grep -i -n "token" file | cut -d':' -f 1
If the token is found, it will return the line number as usual. I want to know how to account for the case when the token does not exist in the text file and the terminal simply outputs nothing when the command is executed.
i.e.
if []
then
echo "This token does not exist in the file"
fi
I hope that's what you need:
result=$(grep -i -n "token" file | cut -d':' -f 1)
if [[ -z "$result" ]]; then
echo "Not found"
else
echo "$result"
fi
My goal is to write a shell script take the users that I have already filtered out of a file and check whether those users have a certain string, and if they do, label them as major, if not, nonmajor. My trouble is coming from my first if statement, and I'm not sure if grep is the right way to go in an if statement. Here is what I have:
(
while read i
do
username=`echo $i | grep -v 'CMPSC 1513' | grep -P -v '(?!.*CPSMA 2923)CPSMA' | cut -d'|' -f2`
fullname=`echo $i | grep -v 'CMPSC 1513' | grep -P -v '(?!.*CPSMA 2923)CPSMA' | cut -d'|' -f3`
id=`echo $i | grep -v 'CMPSC 1513' | grep -P -v '(?!.*CPSMA 2923)CPSMA' | cut -d'|' -f4`
if [ $username ]
then
if grep -q "|0510"
then
echo $username":(password):(UID):(GID):"$fullname"+"$id":/home/STUDENTS/majors:/bin/bash"
else
echo $username":(password):(UID):(GID):"$fullname"+"$id":/home/STUDENTS/nonmajors:/bin/bash"
fi
fi
done
)<./cs_roster.txt
Just some info, this is contained in a while loop. In the while loop, i determine whether the person listed should even be major or nonmajor, and my if [ $username ] has been tested and does return all the correct users. At this point the while loop is only running once and then stopping.
Just remove the square brackets and pass $i to grep:
if echo $i | grep -q "|0510"
In your code sample, grep does not have anything to work on.
The "binary operator expected" occurs because you are invoking the command [ with the arguments "grep" and "-q" (you are not invoking grep at all), and [ expects a binary operator where you have specified -q. [ is a command, treated no differently that grep or ls or cat. It is better (IMO) to spell it test, and when invoked by the name test it does not require that its last argument be ]. If you want to use grep in an if statement, just do something like:
if echo "$username" | grep -q "|0510"; then ...
(Although I suspect, depending on the context, there are better ways to accomplish your goal.)
The basic syntax of an if statement is if pipeline; then.... In the common case, the pipeline is the simple command test, and at some point in pre-history, the decision was made to provide the name [ for the test command with the added caveat that its final argument must be ]. I believe this was done in an effort to make if statements look more natural, as if the [ is an operator in the language. Just ignore [ and always use test and much confusion will be avoided.
You can use this code as an exercise. Write an awk script for it, or start with something like
while IFS='|' read -r f1 username fullname id otherfields; do
# I don't know which field you want to test. I will rest with id
if [[ $id =~ ^0510 ]]; then
subdir=majors
else
subdir=nonmajors
fi
echo "${username}:(password):(UID):(GID):${fullname}+${id}:/home/STUDENTS/${subdir}:/bin/bash"
done < <( grep -v 'CMPSC 1513' ./cs_roster.txt | grep -P -v '(?!.*CPSMA 2923)CPSMA' )
This is nice for learning some bash syntax, but consider an awk script for avoiding a while-loop.
I am trying to work on a bash script that checks for a username in the argument of the script and then outputs the relevant lines from the /etc/passwd and /etc/group files (not the /etc/shadow file). Currently, I am utilizing a if then else loop to check the contents of the /etc/* directory and output the relevant information. My intention was to output simple text line if a match user is not found in the two files, thus a null value. However, it is outputting information that is totally incorrect for what I am looking for.As a new user to BASH, and linux is general, I am sure there are some glaring issues right away. However, I am trying to learn.
Any help with the code of my script or a point in the right direction would be greatly appreciated. Thank you.
#! /bin/bash
USERLOOK='grep -h $USERID ~/etc/* | grep :x:'
grep $1 ~/etc/*
if [ -z $1 ]; then
echo "User not found."
else
echo "$USERLOOK"
fi
exit 0
Finds any lines in /etc/passwd or /etc/group that contain the inputted username:
#!/bin/bash
USERLOOK=$(grep -h "$1" /etc/passwd /etc/group)
if [ -z "$1" ] || [ -z "${USERLOOK}" ]; then
echo "User not found."
else
echo "$USERLOOK"
fi
I want to have the script function where I input ./script
user_to_check. If the username is found, I want to output all lines
where it was found... However, if the username was not found, I wanted
to echo that.
It can be as simple as
#!/bin/bash
grep "^${1}:" /etc/passwd /etc/group
[ $? -ne 0 ] && echo "User : ${1} not found"
As the user name appears in the beginning in both /etc/passwd & /etc/group we placed a ^ in grep to match stuff at beginning and by tradition a : appears just after the username.
Run the script as
./script 'username'
Stop, you're thinking about this all wrong.
A UNIX shell is an environment from which to call UNIX tools with a language to sequence those calls, that is all. The general purpose UNIX tool to manipulate text is awk. So if you need to look for text in a file and have control logic to do anything with it, that should be an awk script, not a shell script. Shells role is to just call awk, something like this:
awk -v user="$1" '
$0 ~ user { line = $0 }
END { print (line != "" ? line : "User not found") }
' /etc/passwd /etc/group
but note that it's trivial with awk to focus the search on just one field, even a different field for each file, unlike how difficult that is in general with grep.