sed command doesn't work every time

theuser

New Member
Joined
Jan 13, 2022
Messages
3
Reaction score
1
Credits
38
Hello Linux community,
I made a script that replaces strings in a file but it behaves very strangely because it worked a few times, but it doesn't most of the time, it just doesn't change the strings. I know that my script is working fine, otherwise it wouldn't have worked. And I have no error in the shell, nothing suspicious.
Note that the sed command doesn't work only in the while loop, maybe there's something wrong about this...

Here's an example of what I want to do : the file A contains "water" in the 1st line, and "milk" in the 2nd line. Running the script will replace all "water" strings in file B by "milk".

Again, I'm pretty sure that my script is okay, I didn't change anything after getting it to work. I checked the file paths, I tried to change the content of file A and file B, I spent hours to find what's wrong. That just doesn't make sense. Here's the script :
Code:
#!/bin/bash

fileA=~/Documents/a.txt    #contains strings matchings
fileB=~/Documents/b.txt    #strings to edit

linenum=4
i=1        #starts at line 1 in fileA

while [ $i -le $linenum ]
do
oldname=$(sed "$i q;d" $fileA)        #takes string from line i in file A

let "i += 1"
newname=$(sed "$i q;d" $fileA)        #takes string from line i+1 in file A


oldname=$(echo "${oldname}" | sed -e 's/[]$.*[\^]/\\&/g' )
#removes regex in the strins by adding a space

sed -i "s/${oldname}/${newname}/g" $fileB
#searches the string oldname in fileB and replace it with newname

let "i += 1"
done

Do you have any idea, or could you at least try the script and tell me if it works for you?
 


I understand what you're trying to do.
You want to read two lines at a time from fileA. The first line is a word to search in fileB for, and if that word is found in fileB - the second line is a word to replace that word with.

However, I can't clearly understand the logic behind any of your code.
To me, it doesn't look like it will do what you're expecting it to do at all. Though I admit, I haven't looked at it that hard. And it is almost 3am here!

Personally, If I was writing this script - I'd read the entirety of fileA, two lines at a time using read, instead of sed.
So you read two lines from fileA to get the pair of words. And THEN you could run a sed command on fileB to perform a search/replace. Which would mean that sed gets called each time we retrieve a pair of words from fileA.
Which, off the top of my head, would look something like this:
Bash:
#!/usr/bin/env bash
while read -r searchWord; do
    read -r replaceWord
    sed -i "s/$searchWord/$replaceWord/g" /path/to/fileB
done < /path/to/fileA
That's the most simple solution.

Or alternatively, you could take a more complex approach and do it with a single sed command.
This way would require you to read fileA, two lines at a time, using read - as we did before, and then we'd populate two arrays.
One array with words to search for (searchArray).
And another array with words to replace with (replaceArray).
As long as there are an even number of words in fileA - the two arrays should always be the same size.
So the first word in the first array (searchArray), would correspond to the first word in the second array (replaceArray). Likewise for the second, third, etc etc.

Once you've got the two arrays of words from fileA - You use another loop, to simultaneously loop through the two arrays and gradually build a string variable, containing a single set of filters/actions for sed, that will search/replace all of the words in one go.
Once the set of filters has been built, you simply pass the filter you built as an argument to a single call to sed, which will search and replace all of the words in one pass-through of fileB.
This approach would be slightly more complex, but also more efficient. As it only requires sed to be ran once on fileB, instead of once for each pair of words.

But it's now well past 3am here and I need to get to bed. So I'm not going to try writing that code right now, I have work soon!
 
Last edited:
Thank you for your reply, I tried your code and mess with it a bit, that seems to do something but I still have the same problem. It doesn't change any string, even though the file is edited (my script did the same thing).
I mean I checked the last modification date of the file (file B), it was edited by the script, but nothing has changed in the script. That's really frustrating.
I didn't try your alternative solution, I'll think about it.

I will try this on another PC, maybe something is messed up on this one, the file system or whatever cr*p I don't know about... Thanks for the help anyway.
 
G'day and welcome @theuser :)

I'm moving this to Command Line (where scripting is also handled), although I see Jas has already found you.

Chris Turner
wizardfromoz
 
Thank you for your reply, I tried your code and mess with it a bit, that seems to do something but I still have the same problem. It doesn't change any string, even though the file is edited (my script did the same thing).
I mean I checked the last modification date of the file (file B), it was edited by the script, but nothing has changed in the script. That's really frustrating.
I didn't try your alternative solution, I'll think about it.

I will try this on another PC, maybe something is messed up on this one, the file system or whatever cr*p I don't know about... Thanks for the help anyway.

Can you post a few lines from your two files, so I can see exactly what you’re dealing with?

Based on your description in your first post, my script assumes fileA has one word per line.
E.g.
Code:
water
milk 
butter
cheese

And then the second file has something like: (just a completely random, contrived example file, because I have no idea what you’re working with)
Code:
Todo: Buy water and butter from the shop.

Then the script reads the first two lines from the file. So water is the word to search for and milk is the word to replace it with. Then we run sed on fileB and water is replaced with milk.
On the next iteration, butter is replaced with cheese.

So after running the script, fileB will contain this:
Code:
Todo: Buy milk and cheese from the shop.

And that works on my Debian 11 Laptop.

If the format of your files is different, then you’ll need to show a more concrete example of what you’re working with and I can help you to get something working.
 
Can you post a few lines from your two files, so I can see exactly what you’re dealing with?

Based on your description in your first post, my script assumes fileA has one word per line.
E.g.
Code:
water
milk
butter
cheese

And then the second file has something like: (just a completely random, contrived example file, because I have no idea what you’re working with)
Code:
Todo: Buy water and butter from the shop.

Then the script reads the first two lines from the file. So water is the word to search for and milk is the word to replace it with. Then we run sed on fileB and water is replaced with milk.
On the next iteration, butter is replaced with cheese.

So after running the script, fileB will contain this:
Code:
Todo: Buy milk and cheese from the shop.

And that works on my Debian 11 Laptop.

If the format of your files is different, then you’ll need to show a more concrete example of what you’re working with and I can help you to get something working.

That's right, you described exactly what I wanted to do. But I finally managed to make your script work (the one in your first post) and it works every time I use it, no matter what files I have.
I didn't use another PC, I don't know what happened actually but I just changed the content of file A. Before, my file contained these strings :
Code:
WATER
MILK
BREAD
RICE
The file B was similar to the example you used (but strings were in upper case). I simply changed the strings in file A and B into lower case, then I ran the script and file B was changed as I wanted...
The cause of the issue is still unknown but well, now it's gone. If I happen to find the cause, I'll edit the post to explain what it was.

Thanks again!
 
Last edited:

Members online

No members online now.

Top