5

I have a text file with each line having some defined number of fields but they can differ from line to line. All I want to do is to add "=" sign in front of every value in the field in that line.

For example INPUT FILE

A   B   C   D   E
P   Q   R   S   T   U
L   M   N   O

OUTPUT FILE

=A  =B  =C  =D  =E
=P  =Q  =R  =S  =T  =U
=L  =M  =N  =O

Also this is just an example, my file contains some lines where number of field are more than 20. How to do this efficiently.

6 Answers 6

8

Assuming your fields contain more than just one letter, with GNU sed:

sed 's/\</=/g' <<END
foo    bar    baz
A      B      C
apple  banana cherry
END
=foo    =bar    =baz
=A      =B      =C
=apple  =banana =cherry

GNU sed's \< regex construct is a zero-width "start of word" marker (the transition between a non-word (or the beginning of the line) and a word character (alnums in your locale or underscore)). So we're replacing the start of each word with the "=" character.

(sed regex reference here)

5
  • Tangentially, I wonder why Perl's regex syntax does not have "start of word" and "end of word" markers. May 14, 2014 at 17:02
  • Maybe \b\w for work around.
    – cuonglm
    May 14, 2014 at 17:29
  • good idea. \b(?=\w) would be more exact. Thanks. May 14, 2014 at 18:08
  • Ah, I forgot to update my comment, I used \b(?=\w) in my answer :)
    – cuonglm
    May 14, 2014 at 18:20
  • Though \< originated in BSDs (ex/grep), it seems it never made it to any BSD sed. It is in GNU sed though. It's not POSIX. May 14, 2014 at 18:23
5

A shorter awk version:

$ awk 'gsub(/([^ ]+)/,"=&",$0)' file
=A   =B   =C   =D   =E
=P   =Q   =R   =S   =T   =U
=L   =M   =N   =O

Explanation

We do a global substitution for each input line:

  • /([^ ]+)/: matchs each fields, because fields is separate by spaces, so this regex match all thing except spaces.

  • "=&": with each fields, add = before it.

& meaning is replaced with character that was matched. From man awk:

gsub(r, s [, t])        For each substring matching the regular expres‐
                        sion  r  in the string t, substitute the string
                        s, and return the number of substitutions.   If
                        t  is  not  supplied,  use  $0.   An  &  in the
                        replacement text is replaced with the text that
                        was  actually matched.  Use \& to get a literal
                        &.  (This must be typed  as  "\\&";  see  GAWK:
                        Effective  AWK Programming for a fuller discus‐
                        sion of the rules for &'s  and  backslashes  in
                        the replacement text of sub(), gsub(), and gen‐
                        sub().)

Update

For @glenn jackman's answer and comment, I add an equivalent version in perl:

$ perl -pe 's/\b(?=\w)/=$&/g' file
=A   =B   =C   =D   =E
=P   =Q   =R   =S   =T   =U
=L   =M   =N   =O
4
  • Note that the awk one removes the blank lines. May 15, 2014 at 6:15
  • @StephaneChazelas: awk 'NF > 0 {gsub(/([^ ]+)/,"=&",$0)}{print}' will keep blank lines.
    – cuonglm
    May 15, 2014 at 6:19
  • Or just awk '{gsub(/([^ ]+)/,"=&");print}', or awk '1+gsub(/([^ ]+)/,"=&")',it's just that you were using the result of gsub as a condition to print. May 15, 2014 at 7:22
  • @StephaneChazelas: Maybe I think a complicated way. Thanks for good point.
    – cuonglm
    May 15, 2014 at 7:43
4

To do this in awk, you could use:

awk '{for (i=1;i<=NF;i++) printf "=%s ",$i;printf "\n"}' filename

Loop over the internal NF (number of fields) variable, printing each field with an equals prepended and a space appended, then after printing all fields, print a newline.

3
  • Hi this works. Thanks a lot. Can you tell why printf is used and not print??? May 14, 2014 at 15:39
  • 2
    print adds a newline by default, printf does not
    – Josh Jolly
    May 14, 2014 at 17:19
  • Note that it changes the spacing of the fields. May 15, 2014 at 6:13
3

Your question is not very clear.

To insert = before each sequence of letters, that would be:

sed 's/[[:alpha:]]\{1,\}/=&/g'

Before any letter:

sed 's/[[:alpha:]]/=&/g'

Before each sequence of non-blanks:

sed 's/[^[:blank:]]\{1,\}/=&/g'

(those are POSIX and portable).

1

Try this simple sed command,

sed 's/\([A-Za-z]\+\)/=\1/g' file

Example:

$ (echo 'A   B   C'; echo 'A C D F') | sed 's/\([A-Za-z]\+\)/=\1/g'
=A   =B   =C
=A =C =D =F

This command will place = sign before A-Z,a-z.

OR

try this command also,

sed 's/\([ ]\+\)/\1=/g; s/^\(.*\)$/=\1/g' file

Example:

$ (echo 'A   B   C'; echo 'A C D F') | sed 's/\([ ]\+\)/\1=/g; s/^\(.*\)$/=\1/g'
=A   =B   =C
=A =C =D =F

This command will replace one or more spaces with one or more spaces plus = sign and also it places = on starting.

1

You can simplify this a bit with GNU awk

awk -v RS='[[:space:]]+' '{printf "=%s%s", $0,RT}' input.file
=A   =B   =C   =D   =E
=P   =Q   =R   =S   =T   =U
=L   =M   =N   =O
1
  • This Works , Can you explain the code? THanks May 14, 2014 at 16:01

You must log in to answer this question.

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