Kit Ho
Kit Ho

Reputation: 26968

How can I append a string into the first occurrence of a pattern?

Add a apple string when i find the first pattern of foo.

Input data:

foofoo
foobaz
foobez

Results:

apple
foofoo
foobaz
foobez

is that possible to do it using bash/sed ?
thanks

Upvotes: 0

Views: 462

Answers (5)

Birei
Birei

Reputation: 36262

Using 'sed':

$ cat infile

foofoo
foobaz
foobez

$ cat script.sed

## The pattern 'foo' found in the line.
/foo/ {
        ## Check hold space, case of being blank, it's the first pattern 'foo' so
        ## I will print the word 'apple' before it.
        x
        /^$/ {
                i\
apple
                g
        }
        ## Go back to pattern space to print at the end of this script.
        x
}

$ sed -f script.sed infile

apple
foofoo
foobaz
foobez

Edit: Add a solution using a one-line sed command.

I don't know how to use the 'i\' command in one line, but next one is similar and it works.

$ sed '/foo/ { x ; /^$/ { g ; s/^/apple\n/ ; x }; x }' infile
apple
foofoo
foobaz
foobez

Upvotes: 1

Not bash/sed but perl, which is a speciality of mine.

perl -pE 'say "apple" if /^foo/ and not $seen_foo++'

For each line, say "apple" if the line starts with "foo" and we have not seen one such line before, then print the line.

Upvotes: 2

yabt
yabt

Reputation: 21

Pure Bash:

nl=$'\n'
str='foofoo
foobaz
foobez
'
echo "${str/foo/apple${nl}foo}"

Upvotes: 1

c00kiemon5ter
c00kiemon5ter

Reputation: 17614

I assume, that list is a file(?). So using just Bash(just for fun, perl is so much more powerful in its expressiveness) I'd do it like this:

#!/usr/bin/env bash

newstr="$1"
filein="$2"
counter=0

while read -r; do
    ((counter++))
    if [[ $REPLY =~ ^foo ]]; then
        printf "%s\n" "$newstr" "$REPLY"
        break # no need to loop anymore
    fi
    printf "%s\n" "$REPLY"
done < "$filein"

# just print the rest of the file
sed -n "$counter,$(wc -l < "$filein")p" "$filein"

use it like this:

$ that_script apples file

Inspired by my answer in a similar question


NOTE: this just looks if the string starts with foo. Place your own pattern, by changing the line below, to whatever suits you:

if [[ $REPLY =~ ^foo ]]; then

Upvotes: 1

nhed
nhed

Reputation: 6001

#!/bin/bash

typeset -i seen_foo=0;
while read line; do
  case "${line}" in
    *foo*)
    let seen_foo++
    [ $seen_foo -eq 1 ] && echo apple
    ;;
  esac
  echo "${line}"
done

Translated the perl answer to bash If you save the above as /tmp/x and your input as /tmp/x1 you would run it like this

bash /tmp/x < /tmp/x1

Upvotes: 1

Related Questions