4

My file currently has

Name.      Address.   Phone number 
Jack.        L.A             1435672
John         L.A.            1465432
Nick.        F.l.            1489756

When the user wants to delete a contact from the list he enters the name of the contact and the program deletes the whole line. When the user wants to modify a contact he enters the name and find the contact and then change it with a new name, address and phone number. I am trying to achieve this using two functions delete and modify.

pa4080
  • 29,831
Abdulaziz Yesuf
  • 143
  • 1
  • 6
  • 2
    Show us some samples of how it is and how it should be! – George Udosen Jan 26 '19 at 07:11
  • That’s fine, but what is your question? – dessert Jan 26 '19 at 07:41
  • For example the file has a line. Jack L.A. 1456233. So when the user enters Jack the code should delete the whole line – Abdulaziz Yesuf Jan 26 '19 at 10:31
  • And another function to modify the name address and phone number – Abdulaziz Yesuf Jan 26 '19 at 10:33
  • I think this is done easily with a spreadsheet program, for example Libreoffice Calc (unless the database is too huge). For the sake of learning you can make a bash shellscript with or without using awk or sed. Anyway, please edit your original question to show us a few lines of the data file with names, addresses and phone numbers and your current version of 'bash code', the shellscript. – sudodus Jan 26 '19 at 11:56

1 Answers1

4

You can use the command sed with syntax like as:

sed "/^\t$name/d" in-file

Where:

  • we must use double quotes when inside the regular expression need to pass a shell variable - $name in this case.

  • ^ will match to the beginning of the line.

  • \t will match to a single tab.

  • the command d at the end will delete each line that match to our regexp /^\t$name/.

You can add -i (or -i.bak) to create the changes in place of the file (or and create a backup copy). Or you can Blueirect the output of the command to anotger file, etc.:

sed "/^\t$name/d" in-file -i.bak
sed "/^\t$name/d" in-file > out-file

More examples:

$ name='Blue'                       # assign a value to the shell variable $name

$ cat in-file                       # output the content of the input file
first line
second line
    Blue
    fourth line
Blue

$ sed "/^\t*$name/d" in-file        # remove the lines that begin ^ with 0 or more tabs followed by the value of $name
first line
second line
    fourth line

$ sed -r "/^\t+$name/d" in-file     # remove the lines that begin ^ with 1 or more tabs followed by the value of $name; enable extended regexp -r
first line
second line
    fourth line
Blue

$ sed -r "/^\t{0,1}$name/d" in-file # remove the lines that begin ^ with 0 or 1 tabs followed by the value of $name; enable extended regexp -r
first line
second line
    fourth line

$ sed -r "/^\t?$name/d" in-file     # remove the lines that begin ^ with 0 or 1 tabs followed by the value of $name; enable extended regexp -r
first line
second line
    fourth line

$ sed -r -e "/^(\t|\s|\s\t|\t\s)?$name/d" -e 's/^\t//' in-file # remove the lines that begin ^ with 0 or 1 tabs, or spaces, or spaces and tabs, or tabs and spaces`; remove the tabs in the beginning of the rest lines 
first line
second line
fourth line

Edit: Here is how to substitute a whole line from the example provided in the updated question. Here is used the sed's substitution command s/regexp/replacement/.

First let's assume we have defined the following sets variables:

old_name='Jack.' old_address='L.A.' old_phone='1435672'
new_name='Tom.' new_address='F.l.' new_phone='875632'

If we need exact match of the line and want to keep the exact format, we can use the following command, that uses capture groups option: (...) -> \1, etc.; additionally the option -r (use extended regular expressions) is applied to simply the syntax (check this question as reference):

sed -r "s/^(\t*|\s*)$old_name(\t*|\s*)$old_address(\t*|\s*)$old_phone(\t*|\s*)$/\1$new_name\2$new_address\3$new_phone\4/" in-file

In this way we capturing the field separators (that in this case cold tabs and/or spaces) and output them in their place within the replacement string.

If we do not need to be so accurate we can use something more simple as the follow (where in the place of the capture groups our regex will expect 0 or more * characters of any type .):

sed -r "s/^.*$old_name.*$old_address.*$old_phone.*$/$new_name\t$new_address\t$new_phone/" in-file

Or even more simple:

sed -r "s/^.*$old_name.*$/$new_name\t$new_address\t$new_phone/" in-file

Example:

$ cat in-file 
Name.   Address.  Phone number
Jack.   L.A.      1435672               
John.   L.A.      1465432
Nick.   F.l.      1489756

$ old_name='Jack.' old_address='L.A.' old_phone='1435672' new_name='Tom.' new_address='F.l.' new_phone='875632'

$ sed -r "s/^(\t*|\s*)$old_name(\t*|\s*)$old_address(\t*|\s*)$old_phone(\t*|\s*)$/\1$new_name\2$new_address\3$new_phone\4/" in-file 
Name.   Address.  Phone number
Tom.    F.l.      875632               
John.   L.A.      1465432
Nick.   F.l.      1489756
pa4080
  • 29,831
  • Is there any way I can replace the whole line with other user inputs for example in place of jack- tom, l.a - f.l and 1435267- 875632. Assuming that tom, l.a and 875632 are stored in $newname,$newaddress and$newphone respectively – Abdulaziz Yesuf Jan 26 '19 at 13:35
  • @A6du2, I've updated the answer. – pa4080 Jan 26 '19 at 14:24
  • I can’t accept the oldaddress and oldphone from the user so is there any way I can read those from a file given the old name – Abdulaziz Yesuf Jan 26 '19 at 15:06
  • @A6du2, yes, you can in several ways, for example you can use the bash builtin read in a way like this: read -r old_name_captured old_address old_phone < <(sed -n "/^.*$old_name.*$/p" in-file), where the first < feeds the std-in of the read command with the content of the "pseudo file" <(...). The default value of IFS= is tabs and spaces so read will assign the three monolithic strings to the tree newly created variables old_name_captured, old_address and old_phone. Here is a clue abut this usage of sed: https://askubuntu.com/a/1113064/566421 – pa4080 Jan 26 '19 at 15:37
  • This works but it brings unexpected results in a file for example when i modify john with name john address tx and number 18638438 the it adds johntx18638438 after tom and nicks phone number – Abdulaziz Yesuf Jan 26 '19 at 16:29