How to make search, enter text and replace a line in bash? - bash

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.

Related

Writing an equivalent of Python's input function in bash

I am trying to write a simple equivalent of Python's input function in Bash.
An example in a Python script would be something like this:
s = input('Please input something: ')
I imagine the call to a Bash equivalent would look like this:
s=$(input "Please input something: ")
This is the implementation that I wrote:
function input {
# $1 is the prompt passed as an argument; in my above example,
# it would be 'Please input something: '
printf "%s" "$1"
read in
echo "${in}"
return 0
}
With the call s=$(input "Please enter something: "), the prompt never prints; instead, the Bash script simply waits for user input without ever displaying the text. Pressing Enter, that is, giving no input, sets s to the prompt itself. What seems to be happening is s captures the output from the line printf "%s" "$1", then reads input which it also echoed back. I have also tried explicitly directing the prompt to stdout with printf "%s" "$1" >&1, but to no avail.
How can I print the prompt first, then capture input and echo it back to the calling function?
You're in luck. It already exists in the form of read -p.
read -p 'Please input something: ' s
To be safe, it's a good idea to use IFS= and -r as well. IFS= makes sure leading and trailing whitespace are retained. -r preserves backslashes so \n isn't interpreted as a newline, or \\ turned into \.
IFS= read -rp 'Please input something: ' s
As to why your function doesn't work, it's because the prompt is being printed to stdout, which is captured. Print to stderr to get it to show up.
input() {
printf "%s" "$1" >&2
read in
printf '%s\n' "$in"
}
A careful scripter will use printf '%s\n' in place of echo. If the user types -n or -e you want those printed, not interpreted as options.

How to edit a particular line based on the input I give in Unix Scripting

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.

Change a whole line in a .csv file

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!

sed with loop to replace certain fields in a file with delimiter :

How should I use the sed command to replace certain fields with delimiter : and run a check to make sure that the user's input can be found within the file & if it can't be found it will loop again.
main_menu #function main_menu
echo "1) choice 1"
echo "2) choice 2"
read choice #read user choice on which choice he wants
if [ $choice -eq 1 ]
then
edit_item #function
read $choice_e #read input
grep -iqs "$choice_e: " Item.txt && echo "item found" #search file to find match
while [[ ! ${choice_e} =~ ^([Item.txt])$ ]]; do #loop to find if input matches search
echo "New Title: " #input new
read choice_n
sed -i 's/^/"$choice_n"\t/' Item.txt #edit the item
done
edit_item
else
echo "error" #return user to input again
fi
The invocation of sed is flawed because of the single quotes mixed with double quotes:
sed -i 's/^/"$choice_n"\t/'
The single quotes mean that the $ (and double quotes) are not interpreted by the shell. What you're probably after is:
sed -i "s/^/$choice_n\t/"
Without knowing exactly which shell and version of sed you're using, it isn't clear whether the \t sequence will be translated to a tab or not. In Bash, you could use the ANSI C Quoting mechanism:
sed -i "s/^/$choice_n"$'\t'/
I don't see where your 'delimiter :' is coming into play at all.

How to extract values from a string on ksh (korn shell)

I have the following input
MyComposite[2.1], partition=default, mode=active, state=on, isDefault=true, deployedTime=2012-05-07T15:35:22.473-07:00
MessageManager[1.0], partition=default, mode=active, state=on, isDefault=true, deployedTime=2012-05-07T15:37:14.137-07:00
SimpleApproval[1.0], partition=default, mode=active, state=on, isDefault=true, deployedTime=2012-05-07T15:28:39.599-07:00
and I have a script that parses the input line by line from a file but I don't have a clue on how I could extract individual parameters from each line into local variables so I can perform additional processes
So far I'm trying the following:
#!/bin/ksh
file="output"
compositeName="foo" ci=0
# while loop while read line do
# display line or do somthing on $line
if echo "$line" | egrep -q '\[[0-9]*\.[0-9]*\].*?(mode=active).*?
(state=on)' then compositeName=$( echo "$line" | egrep '[0-9]*' )
echo "$compositeName"
#echo "$line"
fi
done <"$file"
I'm somwhow lookint to extract only two values from this string, the first word and the float between brackets
ie:
name = MyComposite
version = 2.1
any ideas?
I'm not sure if those line numbers are in the file or not. If not, you can do this:
#!/usr/bin/env ksh
while IFS="," read nameVersion line; do
name="${nameVersion%%\[*}"
version="${nameVersion//*\[+([0-9.])\]*/\1}"
print "name=$name version=$version"
done < "$file"
If the line numbers are in the file, change the name assignment in the above script to name="${nameVersion//+([0-9]).+( )+(*)\[*/\3}"

Resources