2

I have a file example.txt which contains multiple lines:

Larry is funny!
Funny, I've no glue!
Look here!
Tom has no pants.
The underpants are in the drawer.
Pants are in the closet!

After creating a file with 4 random line numbers

sed -n '=' example.txt | shuf | head -3 > line_numbers.txt

Assuming the line numbers in line_numbers.txt contains

1
3
6

I want to edit example.txt by appending the word WORD at each line from line_numbers.txt which contains the full word "pants" (not partial words like "underpants").

How can I do this?

I wish the example.txt looks like this

Larry is funny!
Funny, I've no glue!
Look here!
Tom has no pants.
The underpants are in the drawer.
Pants are in the closet!WORD

Edit:

to find only full words, you have to write your source_word like \<source_word\>.

Other possible example:

I have another file which contains these lines:

I love apples.
You hate pineapples.
Apple pie is delicious.
Why do you do not like eating an apple?
We prefer pears to apples.
How many apples do you want to eat?
I have to bake three apple pies for sunday.

I have a list with three random line numbers

6
2
4

I only want to add at the end each line --OK, if the line contains the full word apples.

The output must look like this:

I love apples.
You hate pineapples.
Apple pie is delicious.
Why do you do not like eating an apple?
We prefer pears to apples.
How many apples do you want to eat?--OK
I have to bake three apple pies for sunday.
9
  • It's unclear how you want to use the line numbers. Appending something to each line that contains pants can be done with sed '/pants/ s/$/WORD/'.
    – they
    Jan 24 at 10:30
  • I only want to append WORD on line 6 and not every line which containts the word "pants". Jan 24 at 10:32
  • Please edit your question to add requested information or clarification. Please also add more details in what way it "is not working".
    – Bodo
    Jan 24 at 10:37
  • 1
    If the input line was sweatpants are comfortable and the line number was a match should WORD be added to the end of that line? i.e. do you want to match on partial words or only full words?
    – Ed Morton
    Jan 25 at 13:26
  • 1
    OK - all of the answers posted so far, including the one you accepted, do partial word matches instead of full word and so will fail given the case I mentioned. You should update your sample input/output (or maybe more appropriately ask a new question) to cover that case and any others you can think of so we have something to test a potential solution against. With these sorts of questions it's always trivial to match the text you want but harder to not match similar text you don't want so it's very important when asking such a question to really THINK about the possible input.
    – Ed Morton
    Jan 25 at 14:06

4 Answers 4

4

I expect there's a way in sed too, but personally I find awk much easier for this sort of more complex manipulation:

awk 'NR==FNR{a[$1]++; next} 
    { 
        s=tolower($0); 
        if(FNR in a && s~/pants/){$0=$0"WORD"}
    }1' line_numbers.txt examples.txt 
Larry is funny!
Funny, I've no glue!
Look here!
Tom has no pants.
The underpants are in the drawer.
Pants are in the closet!WORD

If you have GNU awk (gawk, the default on Linux systems), you can do this to edit the file in place:

gawk -i inplace 'NR==FNR{a[$1]++; print; next} 
                { 
                    s=tolower($0); 
                    if(FNR in a && s~/pants/){$0=$0"WORD"}
                }1' line_numbers.txt examples.txt 

Or, slightly simpler if you don't mind losing the contents of line_numbers.txt:

gawk -i inplace 'NR==FNR{a[$1]++; next} 
                { 
                    s=tolower($0); 
                    if(FNR in a && s~/pants/){$0=$0"WORD"}
                }1' line_numbers.txt examples.txt 
6
  • This was exactly what I wanted! Thank you! Can I also combine this code with a sed line? Jan 24 at 10:45
  • 1
    @RamónWilhelm see update for how to edit the original file, if that was what you meant.
    – terdon
    Jan 24 at 10:48
  • The last two codes are exactly the same code. I receive awk: not an option: -i as output. Jan 24 at 10:56
  • @RamónWilhelm they are almost exactly the same code, there is an extra print in the first one: ` NR==FNR{a[$1]++; print; next} . OK, if you get that error, you don't have GNU awk` or you're not using it. WHat operating system are you on? Do you have gawk?
    – terdon
    Jan 24 at 11:00
  • 1
    @RamónWilhelm yay!
    – terdon
    Jan 24 at 11:29
3

The following pipeline, which is a modification of yours, outputs a sed script that performs your edit:

sed -n '=' file | shuf -n 3 | sed 's,$, { /\\<pants\\>/ s/$/WORD/; },'

Or, equivalently,

awk '{ printf "%d { /\\<pants\\>/ s/$/WORD/; }\n", NR }' file | shuf -n 3

This could, for example, generate

6 { /\<pants\>/ s/$/WORD/; }
5 { /\<pants\>/ s/$/WORD/; }
1 { /\<pants\>/ s/$/WORD/; }

This script applies a substitution that adds WORD at the end of each line matching the pattern pants, if that pattern occurs on any of the randomly selected lines.

Running this is a matter of reading it with sed -f:

sed -n '=' example.txt | shuf -n 3 | sed 's,$, { /\\<pants\\>/ s/$/WORD/; },' |
sed -i -f /dev/stdin example.txt

or, with my awk-based variant:

awk '{ printf "%d { /\\<pants\\>/ s/$/WORD/; }\n", NR }' example.txt | shuf -n 3 |
sed -i -f /dev/stdin example.txt

No intermediate file is needed.

Replace pants with apples and WORD with --OK to address your updated query.

1

Here is a oneliner (albeit a little long!).

Assuming that your text file is "tfile" and the index file is ifile, then:

awk 'BEGIN{i=0;p=0}{if(FNR==NR){a[i++]=$1} else {if(a[p]==FNR){p++;g="";if(index($0,"Pants")){g="WORD"};  print $0,g}else{print $0}}}' ifile tfile

and you will get:

Larry is funny! 
Funny, I've no glue!
Look here! 
Tom has no pants.
The underpants are in the drawer.
Pants are in the closet! WORD 
1

With GNU sed, we may construct sed code from the line numbers file and apply them on the data file:

sed -f - <<\eof line_numbers.txt |\
sed -f - example.txt
  1i /pants/I!b
  s/$/ba/
  $a b;:a;s/$/WORD/
eof

Another method is where we transcribe a sed command per line number

sed -e 's:.*:&s/pants.*/\&WORD/I;t:' line_numbers.txt |
sed -f /dev/stdin example.txt

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.