1

I think I found some GNU solutions but I need BSD sed solutions.

What I want to do is replace the entire word at once. If the word is "clayii", and my code is sed 's/c/k/g;s/l/i/g;s/a/e/g;s/y/i/g;s/k/o/g', I want it do produce "kieii", but it produces "oieiii" for obvious reasons. On the last section, it searches for k and finds it in the beginning, but if it searched the whole word, it would never do that.

Obviously, "clayii" will be different all the time, I want it to replace individual letters, but not start from the beginning, if it has already replaced the first n and then finds on in the beginning it should not start over. So basically ignore what's been replaced already, if that's detectable.

Is there a solution for this?

3
  • use -E and don't worry about BSD sed. Dec 1, 2015 at 23:51
  • this may seem obvious but if you don't want sed to replace individual letters, then don't tell it to do that. either search and replace entire words, or restrict the s/// command to operate only on matching words.
    – cas
    Dec 1, 2015 at 23:51
  • @cas I don't think you understand, I want it to replace individual letters, but not start from the beginning, if it has already replaced the first four it should not start over. Dec 1, 2015 at 23:53

3 Answers 3

2

Maybe use y// (sed's built-in tr command) insteaad of s///:

$ echo clayii | sed -e '/clayii/ y/clayk/kieio/'
kieiii

Note that the y// command will still apply to the entire line, not just to the matching word.

9
  • Where do I put all the letters? It can be up two 200 letters. I don't see how the command works similar to sed 's/c/k/g;s/l/i/g;s/a/e/g;s/y/i/g;s/k/o/g' at all? Dec 2, 2015 at 0:09
  • if your solution involves 200 search-and-replace commands for individual letters (how do you have that many different letters anyway?) then you probably ought to rethink the problem.
    – cas
    Dec 2, 2015 at 0:12
  • I have accented and umlauted letters. It adds up. Dec 2, 2015 at 0:15
  • regardless of the number of letters, I still think this sounds like an XY problem (mywiki.wooledge.org/XyProblem). What is it that you are actually trying to do?
    – cas
    Dec 2, 2015 at 0:17
  • I know what an XY problem is, I don't think is one. It's nothing important, I just wanted to scramble words but choose exactly which letter turns into another letter, I didn't think when I first wrote the script, but it's starts replacing things that are already replaced when it matches them. But like I said, it's nothing important. Dec 2, 2015 at 0:23
0

With BSD sed, you can use:

sed "s/[[:<:]]clayii[[:>:]]/kieii/g" /path/to/file
2
  • Where Do I put all the letters though? As you can see in my question, I wanted it to be like 's/c/k/g;s/l/i/g;s/a/e/g;s/y/i/g;s/k/o/g' which means c becomes K, l becomes i, a becomes e and y becomes i. I don't see how that fits into your command. Dec 2, 2015 at 0:07
  • 1
    Sorry; I misread the question and thought it was about word boundaries in BSD sed, which comes up from time to time. It sounds like you're looking for something like tr or sed's y//.
    – DopeGhoti
    Dec 2, 2015 at 0:10
0

you can loop over it:

echo  here is a pat and a tern and a pattern     |
sed  -e'1{H;x;s/\(.\).*/\1pattern\1replace/;x;}' \
-eG  -e'/\(.*\)\(.*\n\)\(\n\1\)\n/!{P;d;}'       \
     -e's//\3\2/;t-'                             \
-e:- -e's/\(\n\)\(.\)\(.*\n\)\(.\)/\4\1\3/;t-'   \
     -e's/\n//;P;d'

here is a pat and a tern and a replace

That does the replacement char by char progressing left to right. It shifts the first delimiter to the right of the replaced character for each substitution. You can see what I mean if you stick a look command in just before the loop tested substitution after -e:-:


here is a pat and a tern and a \npattern\nreplace$
here is a pat and a tern and a r\nattern\neplace$
here is a pat and a tern and a re\nttern\nplace$
here is a pat and a tern and a rep\ntern\nlace$
here is a pat and a tern and a repl\nern\nace$
here is a pat and a tern and a repla\nrn\nce$
here is a pat and a tern and a replac\nn\ne$
here is a pat and a tern and a replace\n\n$
here is a pat and a tern and a replace

If you really are looking for a sort of translation thing, you can do that, too. I wrote this earlier as an answer to another question:

It looks doable - you just have to sort of shift-in/shift-out:

echo can ccccc ccccccccclayii sed clay ignore \
     every cclayii thing but the matching word\
     - cclayiicclayii |
sed     -e'y/ /\n/' \
-eh     -e's/\(cclayii\)\1*/ & /g;x;s// /g;s/^/ /' \
-ex     -e's//./;s/\([^ ]* *\)\{2\}/\1 /g;s/^/ /'  \
        -e'y/clayk/kieio/;G;t$' -e:$  \
        -e'/^ \n /{s///;y/ \n/\n /;}' \
-et     -e's/^ *\([^ ]*\) \(.* \n [^ ]*\) /\2\1/;t$'

can ccccc ccccccckkieiii sed clay ignore every kkieiii thing but the matching word - kkieiiikkieiii

...it isn't easy, though.

That one loops a little bit, too, but not nearly as much.

As is true of most complicated problems, though, it is way easier if you use two seds:

echo can ccccc ccccccccclayii sed clay ignore \
     every cclayii thing but the matching word\
     - cclayiicclayii |
sed -e's/\(cclayii\)\1*/\n&\n /g;G;s/^/ /'|
sed -e'/^ /!y/clayk/kieio/;/./{H;d;}' \
    -e'x;s/\n \{0,1\}//g'

can ccccc ccccccckkieiii sed clay ignore every kkieiii thing but the matching word - kkieiiikkieiii

With a BSD sed you'll want to use a literal newline in place of the n in the \n escapes in the right-hand substitution for the first sed there.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .