LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Mistake with sed espression is saving part of pattern (https://www.linuxquestions.org/questions/programming-9/mistake-with-sed-espression-is-saving-part-of-pattern-783533/)

zizou86 01-20-2010 11:53 AM

Mistake with sed espression is saving part of pattern
 
Hi all,

got a textfile with : as delimiters in between fields. e.g.

1:2:3:4:5:6
Thomas Cruise:John:David:Peter:Betty:Jane

The names may or may not contain white spaces.

I am required to substitute any one of these names in the file with a new one inputted by user.

e.g. to change John to Johnny, David to Beckham, etc. without touching any of the other names in the same line. Just one at a time.

So here's the sed expression I was trying out with:

sed -i "s/<\(.:.:\)David>/$\1Beckham/" names.txt
I also tried:

sed -i "s/<\(.*\)David>/<\1Beckham>/" names.txt

All to no avail. No error mistake, just nothing gets substituted. I am really lost and seem to be missing some crucial concept.

I can only get the first field, which is Thomas Cruise, to sub. It will be very helpful if someone can also explain why there are $ and < > in the 2nd half of the sed expression ie. the new words to sub in.

Please kindly assist.

Thank you.

Regards.

ForzaItalia2006 01-20-2010 12:09 PM

Hey,

Quote:

Originally Posted by zizou86 (Post 3833774)
1:2:3:4:5:6
Thomas Cruise:John:David:Peter:Betty:Jane

sed -i "s/<\(.:.:\)David>/$\1Beckham/" names.txt
I also tried:

sed -i "s/<\(.*\)David>/<\1Beckham>/" names.txt

Why do you use the '<' and '>' characters?

Here's first of all a very _simple_ version of a replace statement:

# sed 's/David/Beckham/g' names.txt

to replace each occurence of David with Beckham (g extension)

I'm not sure if that already serves your purpose, but you could possibly use it as a base for your work ... By the way, if it's important for you to update a specific column, maybe awk is a better choice.

- Andi -

zizou86 01-20-2010 12:17 PM

Hi,

Sorry have to explain abit more.

I might have repeated names in one line. e.g.:

Thomas Peters:Thomas Cruise:Thomas Peters:Betty:Jane


Hence I have to use the /( and /( characters, so that I can go specify, for example Thomas Peters in column 3 will get edited to Thomas John or something.

I have to be able to exactly pinpoint which column is being edited, and the rest of the other columns cannot be edited. Only that column.

I used sed because sed is able to directly edit a text file, while awk seems to require a temporary storage which is something that I am reluctant to implement.

THanks for help.

pixellany 01-20-2010 12:20 PM

Please post a sample of the actual file, and an example of what you want the new output to be.

Go here for a really good SED tuturial:
http://www.grymoire.com/Unix/

David the H. 01-20-2010 12:25 PM

I think I'd reconsider the decision not to use awk. awk handles regularly delimited fields like this much better than sed.

And there are ways to avoid temporary files. You can set it inside a bash script and have the output saved to a temporary variable first, for example.

zizou86 01-20-2010 12:28 PM

Hi, sorry if its kind of vague.

e.g.

User input -

-----------------------
Line to edit: 2
Column to edit: 2
New value: Timmy Peter
-----------------------

Code:

Sample file (many lines of such stuff):
Thomas Peters:Thomas Cruise:Thomas Peters:Betty:Jane
Peter:David:John:Peter:Jane

Sample output based on above user input:
Thomas Peters:Thomas Cruise:Thomas Peters:Betty:Jane
Peter:Timmy Peter:John:Peter:Jane

Hence, the shell script will edit Line 2, Column 2 and replace the original David with the new Timmy Peter.

Thanks.

pixellany 01-20-2010 12:37 PM

Since you have nice lines and columns, you might be better off with AWK. The site I linked has a good tutorial.

Part of the key to this is deciding if something is to be changed based on position or content.

ghostdog74 01-20-2010 07:48 PM

Code:


awk 'BEGIN{
    OFS=FS=":"
    printf "Line to edit: "
    getline linenum <"-"
    printf "Column to edit: "
    getline colnum <"-"
    printf "New value: "
    getline newval <"-"
}
NR==linenum {
    $(colnum) = newval
}1'  file

output

Code:

$ ./shell.sh
Line to edit: 2
Column to edit: 2
New value: Jane Doe
Thomas Peters:Thomas Cruise:Thomas Peters:Betty:Jane
Peter:Jane Doe:John:Peter:Jane


iPenguin 04-28-2010 04:57 PM

Hello zizou86,

I created a script that shows how you can parse/replace a name from a delimited file. You can use it to glean methods for your own script. Sorry its a little long. Cheers.

What the script does :
- creates a sample delimited text file of names { delimiter = : }
- parses the names to numbered lines and displays to the user
- requests the user choose a name (by line number), and confirms choice
- prompts for a new name, shows old and new names, and confirms
- changes the old name to the new name in the file
- displays the sample file to the user to show the physical changes

#!/bin/sh
#
# fx
#

# --- create a sample text file with data --- #

# set the name of the input file where the substitution will occur
ifile=tx


# the header message for the user
msg='This is a list of names from which one can be chosen for substitution.\
The names are numbered for reference.\
When you have found a name to be changed, remember the number and press the Q key.\n\n'

# start with a fresh sample file
cat /dev/null > $ifile

# set the delimiter
dm=':'

# create a set of names to write into sample file
buf=
for token in 'Joe Thomas' 'Jane Thomas' 'Robert Thomas' 'Myrna Thomas' 'Edward Thomas' 'Gus Sr. Thomas' 'Bud II Thomas'
do

buf="$buf$token:"

done

# write the names to the sample file
echo $buf > $ifile


# show the user the list of names and ask for a choice of the one to be changed
#
# note how the msg is placed before the first numbered line
#
cat $ifile | sed 's/:/\n/g' | cat -b | sed '1s/^\(.*\)$/'"$msg"'\1/' | less


# request the number from the user
echo -e "\033c"
echo 'Enter the number of the name to be changed and press the [ Enter ] key.'
echo -e "Or just press the [ Enter ] key to exit and make no changes.\n"

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# get the choice (a line number)
#
read uchoice

# test that the choice is a number only
tst=`echo $uchoice | sed 's/[^0-9]//g'`

# qualified choice
if [[ $tst == $uchoice && ${#uchoice} -gt 0 ]];then

# parse the old name
oldname=`cat $ifile | sed 's/:/\n/g' | sed $uchoice\!d`

# show the choice and get confirmation from the user
echo -e "\033c"
echo -e "This is your choice : $oldname\n"

echo 'IF this choice is CORRECT and you want to change the name, then enter the NEW NAME and press the [ Enter ] key.'
echo -e "Otherwise if this choice is NOT CORRECT then just press the [ Enter ] key and no changes will be made.\n"

# get the new name
read newname

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# qualified new name
if [[ $newname ]];then

# confirm with user
echo -e "\033c"
echo -e "The OLD NAME to be changed is : $oldname\n"
echo -e "You chose this NEW NAME to replace the old name : $newname\n"
echo 'IF this is correct then press the [ Y ] key, then the [ Enter ] key.'
echo 'IF NOT correct then just press the [ Enter ] key and no changes will be made.'
echo

# get the users choice to proceed or not
read confirmed

fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# qualified name
if [[ $newname && $confirmed ]];then

# tmp file
dts=`date "+%Y%m%d%H%M%S"`; tmpfile="oldversion-${dts}-${ifile}"

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# backup the original file and
# replace the old name with the new name in the file
#
if [[ $newname ]];then
cat $ifile > $tmpfile
cat $tmpfile | sed 's/:'"$oldname"':/:'"$newname"':/g' > $ifile
fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# show and tell
echo -e "\033c"
echo -e "The old name ($oldname) has been changed to ($newname) in file ($ifile).\n"
cat $ifile

else
echo 'Cancelled operation, no changes were made.'
fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

zizou86 04-29-2010 05:53 AM

Hey great thanks...

Nah long is good. Allows me to learn more =)

Thank you for bothering to dig up an old thread and posting a reply. Really appreciate it.

I shall go and play around with it when I have the time.

Thanks alot.


All times are GMT -5. The time now is 03:45 PM.