I want to create a shell script that changes a whole line according to input that user gives. I have a contacts.csv file that includes First Name,Last Name,Phone Number
For example a random contact
John,Doe,2103485922
So I want user to type the Last Name of a contact then script deletes the whole line that contains his last name and then insert a whole new line with new data.
For example, I want the above contact to be deleted if user types Doe (Last Name) in the input and then type a new contact. For example Sylvester,Stallone,1414246551.
Any clue?
I have tried this but it doesn't work like I want to:
#!/bin/bash
echo "Tell Me The Contact you want to delete"
read name | grep -evx $name >> contacts.csv
echo "Please type a valid first name Press Enter,Last Name Press Enter and
Phone number"
read fname
read lname
read phone
[[ $fname =~ ^[[:upper:]][a-z]+$ ]] || exit 1;
[[ $lname =~ ^[[:upper:]][a-z]+$ ]] || exit 2;
[[ $phone =~ ^[[:digit:]]+$ ]] || exit 3;
echo "$fname,$lname,$phone" >> contacts.csv
It seems like your question focuses on the ability to delete a line from the input file. Probably the most straightforward approach is with sed -i.
For example:
$ cat test.csv
one,two,three
four,five,six
seven,eight,nine
$ name=five
$ sed -i -e "/,${name},/d" test.csv
$ cat test.csv
one,two,three
seven,eight,nine
$
I hope this helps. Of course you ought to think about what happens if multiple last names match. But I think this answers your immediate question about how to delete a line from a file given a pattern.
Good luck!
Related
I've been trying to write a bash code (experimenting) where bash will ask (Enter Text) and the user will enter a certain text lets say (I am new) and the text (I am new) will be moved to a line called User=I am new.
So, here is a cfg file named xyz.cfg
User
Name
Address
Country
and here is the bash script called test and with only echo $Input > $file the bash replace the whole file with the entered text but I want to keep the config as it is and add the Enter Text: value to the line User but this doesn't help, the code below,
#! /bin/sh
file=/root/xyz.cfg
echo "Enter text:"
read Input
echo $Input > $file **(confused here)** **(it replaces the whole cfg)**
Another line I thought of is here, but it doesn't work. I am not good with these so I hope it's solved; I tried searching the web with zero luck.
(doesn't work)
#! /bin/sh
file=/root/xyz.cfg
echo "Enter text:"
read Input
echo $Input > sed '/User/a' xyz.cfg
(doesn't work)
#! /bin/sh
file=/root/xyz.cfg
echo "Enter text:"
read Input
echo $Input > sed '/User/a' $file
Edit:
When a someone is asked for Enter Text: while running the bash script ./test and the someone typed Entered Text from bash promot the entered $Input (Entered Text from bash promot) should move to xyz.cfg and add the line to the Variable User:
Finally, the xyz.cfg should look like
User: Entered Text from bash prompt
Name
Address
Country
Before it looked like this,
User:
Name
Address
Country
Edit2: This GIF might explain what I need.
This should do the trick:
#!/bin/bash
FILE=/tmp/test.cfg
echo -n "Enter text: "
read INPUT
sed -i "s/User:/& $INPUT/" "$FILE"
This uses sed to do an in-place search / replace (-i) which appends the entered text after the first occurence of User: on each line within $FILE.
& refers to the matched portion of the text - it's essentially saying "replace <thing> with <thing> <entered text>."
If you need to prompt for text each time a matching User: line is encountered, you can use the following approach:
#!/bin/bash
FILE=/tmp/test.cfg
ORIGINAL=$(cat "$FILE")
truncate -s 0 "$FILE"
while read LINE; do
if `grep -q 'User:' <<< "$LINE"`; then
echo -n "Enter text: "
read INPUT < /dev/tty
sed "s/User:/& $INPUT/" <<< "$LINE" >> "$FILE"
else
echo "$LINE" >> "$FILE"
fi
done <<< "$ORIGINAL"
This second approach does the following:
Reads the entire file contents into a variable;
Removes the existing file contents;
Loops over each line of the original content, and:
If the line contains User:, prompt for and append the custom text;
Append the line to the file.
I have wrote a program in bash, where there will be details of the students in a file and on passing input as roll no to it I need to edit that particular line in the file.
But when I tried by passing the roll no, it is displaying the whole file to me for editing when condition matches.
Here is my program:
#!/bin/bash
input="/home/kalyan/Desktop/Exercise/studet.txt"
while IFS=":" read -r rollno name s1 s2 s3
do
echo "$rollno"
done < "$input"
read -p "Enter the Roll No:" rollno1
if [ "$rollno"-eq"$rollno1" ]; then
nano studet.txt
cat studet.txt
else
echo "Doesn't match"
fi
or this program
#!/bin/bash
file="/home/kalyan/Desktop/Exercise/"
FILE="/home/kalyan/Desktop/Exercise/studet.txt"
echo "file to be processed $FILE"
cat $FILE
echo "Reading Roll Number:"
read -r rollno;
if grep $rollno /home/kalyan/Desktop/Exercise/studet.txt
then
echo "Roll No exists"
else
echo "Roll No doesn't exists"
fi
Here I'm trying to get a record of a student based on the roll no as input.
when the roll no matches I'm displaying his rollno, name, marks of three subjects(s1,s2,s3).
Now I need to edit the line which matches the criteria.
Not sure I understand fully what you are doing, but I would do (based on title of the question):
line_number=`grep -n "^$rollno\$" /tmp/a | cut -d : -f 1 "$input"`
nano +"$line_number" studet.txt
Is this last file the same as $input?
I'am not sure if this what you want to have... but say that you want to change a user name depending on its id given as input while running the program:
studet.txt
1:surname1:name1:age1
2:surname2:name2:age2
3:surname3:name3:age3
script.sh
#!/bin/bash
read -p "Enter the Roll No:" rollno
read -p "Enter new name:" name
awk -F ":" -v roll="$rollno" -v name="$name" 'BEGIN {OFS = ":"} $1==roll {$3=name}1' studet.txt > testfile.tmp && mv testfile.tmp studet.txt
The above script will ask the user to pass rollno (exp 1) and name values.
Then awk commad will check if the given rollno exists in the file first fileds (file will be splited into fields using : separator), if this rollno exists the third field of the same line will be changed by the value name the user passed before.
Give it a try by passing 1 and then some string and then check your file.
i have script. In this script i made search and replace of words. Word by word until word 'end'. It is ok and it works. You can see body of my script:
#!/bin/bash
end=end
until [ "$first" = "$end" ];do
echo "please write first word";
read first
if grep -q "$first" *txt; then
echo "word is exists"
grep "$first" *txt
echo "please write second word";
read second
sed -i 's/'"$first"'/'"$second"'/g' *txt
else
echo "second word does not exists"
exit 1
fi
done
It works for me. I have in the result console, where I can endlessly loop words, but if i want to do something like this: How can i write multiple words in line.
For example: "dog" "cat" "fish"
And search and replace all of these words. How can do it? For example, if i need to replace on these words ("elephat" "mouse" "bird"). How can you do it?
I mean search and replace words, like arguments.
You just need a loop to process the arguments.
Assuming you run the script passing pairs of original replacement words (myscript.sh original_word1 replacement1 original_word2 replacement2 ...) it would be something like the following:
while [[ $# -gt 1 ]]
do
original="$1"
replacement="$2"
# your code for actually replacing $original with $replacement
shift # discard already processed original arg
shift # discard already processed replacement arg
done
Note that if the user passes a last original word without replacement the script will just ignore it
Your English is rough, but I think you want to be able to prompt for multiple words, and replace them with a new set?
The below code will let you run a program like replace_words one two three and then be prompted for a list of words to replace, e.g. 1 2 3. After that, it exits.
declare -a replace_list=( "$#" ) # get the replace list as passed arguments
echo -n "Enter words to replace with: "; read -ra sub_list
for ((i=0; i < "${#replace_list[#]}"; ++i)); do
if grep -q "${replace_list[$i]}" *txt; then
echo "first word is exists"
sed -i "s/${replace_list[$i]}/${sub_list[$i]}/g" *txt
else
echo "${replace_list[$i]} does not exists"
exit 1
fi
done
I have a below file which containing some data
name:Mark
age:23
salary:100
I want to read only name, age and assign to a variable in shell script
How I can achieve this thing
I am able to real all file data by using below script not a particular data
#!/bin/bash
file="/home/to/person.txt"
val=$(cat "$file")
echo $val
please suggest.
Rather than running multiple greps or bash loops, you could just run a single read that reads the output of a single invocation of awk:
read age salary name <<< $(awk -F: '/^age/{a=$2} /^salary/{s=$2} /^name/{n=$2} END{print a,s,n}' file)
Results
echo $age
23
echo $salary
100
echo $name
Mark
If the awk script sees an age, it sets a to the age. If it sees a salary , it sets s to the salary. If it sees a name, it sets n to the name. At the end of the input file, it outputs what it has seen for the read command to read.
Using grep : \K is part of perl regex. It acts as assertion and checks if text supplied left to it is present or not. IF present prints as per regex ignoring the text left to it.
name=$(grep -oP 'name:\K.*' person.txt)
age=$(grep -oP 'age:\K.*' person.txt)
salary=$(grep -oP 'salary:\K.*' person.txt)
Or using awk one liner ,this may break if the line containing extra : .
declare $(awk '{sub(/:/,"=")}1' person.txt )
Will result in following result:
sh-4.1$ echo $name
Mark
sh-4.1$ echo $age
23
sh-4.1$ echo $salary
100
You could try this
if your data is in a file: data.txt
name:vijay
age:23
salary:100
then you could use a script like this
#!/bin/bash
# read will read a line until it hits a record separator i.e. newline, at which
# point it will return true, and store the line in variable $REPLY
while read
do
if [[ $REPLY =~ ^name:.* || $REPLY =~ ^age:.* ]]
then
eval ${REPLY%:*}=${REPLY#*:} # strip suffix and prefix
fi
done < data.txt # read data.txt from STDIN into the while loop
echo $name
echo $age
output
vijay
23
well if you can store data in json or other similar formate it will be very easy to access complex data
data.json
{
"name":"vijay",
"salary":"100",
"age": 23
}
then you can use jq to parse json and get data easily
jq -r '.name' data.json
vijay
I am new to bash scripting. I have a script that i am working on for a school project and its not working as expected. I keep receiving a error on my if then statements.
#!/bin/bash
echo –e “Would you like to add a new employee’s information? y/n \n”
read EMPLOYEE
if [ $EMPLOYEE = “y” –o $EMPLOYEE = “Y” ]
then
echo –e “Please enter employee’s first name \c”
read FIRST
echo –e “Please enter employee’s last name \c”
read LAST
echo –e “Please enter empolyee’s ID \c”
read ID
echo –e “$FIRST\t$LAST\t$ID” >> database
fi
echo –e “Would you like to search for an employee? y/n \n”
read SEARCH
if [ $SEARCH = “y” –o $SEARCH = “Y” ]
then
echo –e “Enter the first name, last name or employee ID to search for. \c”
read WORD
grep “$WORD” database
fi
With even a bash version 3 the following should work as you intended and be somehow shellitical correct ;-)
#!/bin/bash
printf "Would you like to add a new employee’s information? y/n \n"
read -r EMPLOYEE
if [ "$(tr '[:upper:]' '[:lower:]' <<<"$EMPLOYEE")" = "y" ]
then
printf "Please enter employee’s first name : \c"
read -r FIRST
printf "Please enter employee’s last name : \c"
read -r LAST
printf "Please enter empolyee’s ID : \c"
read -r ID
printf "%s\t%s\t%s" "$FIRST" "$LAST" "$ID" >> database
fi
printf "Would you like to search for an employee? y/n \n"
read -r SEARCH
if [ "$(tr '[:upper:]' '[:lower:]' <<<"$SEARCH")" = "y" ]
then
printf "Enter the first name, last name or employee ID to search for. : \c"
read -r WORD
grep "$WORD" database
fi
Notes on refactoring/repair:
Do not rely on echo -e in most cases printf works better and looks more like coding,
use read -rto mot mangle backslashes on input,
quote variables from input (with real ASCII quote characters), as the shell parser otherwise does funny things,
do not test against y and Y but simply lowercase the string received to only compare one variant.
Use some indent concept to track, and
use a shell linter as suggested by a commenter already (that one works nicely currently).
The above code does have no errors indicated in the above mentioned linter.
Small task for as exercise for the reader (thanks andlrc :)
Use lowercase variable names and I amend meaningful names
Enjoy the learning of the shell coding!