4

I'm trying to split my second column in the file below after every 4 characters.

file.txt

>1A    THISISATEST
>1B    THATISATEST

desired output:

>1A    THIS    ISATEST
>1B    THAT    ISATEST

After searching and attempting to modify, I tried to use this sed command: sed 's/(.{4})(.{7}).*/\2 \3/' file.txt. However, I can't seem to get it to work. Am I missing something? However, if you have an awk suggestion, that would also be helpful. Also, please explain your suggestions. I'm in the learning process of awk and sed.

2
  • You just needed a \ in front of each { and }. However, you should anchor the expression with ^ per jimmij's post. Otherwise, sed will match a random set of 4 and then 7 characters.
    – Otheus
    Commented Dec 30, 2015 at 17:27
  • Does the awk solution I gave works for you ?
    – iamauser
    Commented Dec 30, 2015 at 18:00

5 Answers 5

2

Here is a solution with awk. It separates first four characters and rest of the 2nd column into two variables and print them.

]$ awk '{s=substr($2,1,4)}{g=substr($2,5,length($2))}{print $1,s,g}' file.txt
1A THIS ISATEST
1B THAT ISATEST
1
  • 1
    This worked perfectly. Commented Dec 30, 2015 at 18:10
2

With sed:

sed 's/^[^ ]\+ \+[^ ]\{4\}/&\t/'

How it works:

  • ^: beginning of the line
  • [^ ]\+: not space character matched at least one time
  • \+: space character matched at least one time
  • [^ ]\{4\}: not space character matched exactly four times
  • &: everything matched between previous //
  • \t: tab

Output:

>1A    THIS ISATEST
>1B    THAT ISATEST

Posixly correct:

sed 's/^[^ ][^ ]*  *[^ ]\{4\}/&\t/'

The pattern + is GNU extension, so one need to simulate it with repeated character and a * to be posix compatible.

9
  • For some reason I can't get this to work appropriately. Commented Dec 30, 2015 at 17:39
  • The lines in my file actually start with a '>'. I will change my question Commented Dec 30, 2015 at 17:41
  • There is no error, but I am not getting the desired split. The file looks that same as the input Commented Dec 30, 2015 at 17:41
  • @stellar01 The > shouldn't change anything unless there are additional spaces after >. If you run example from the question with my command what is the output?
    – jimmij
    Commented Dec 30, 2015 at 17:43
  • 1
    @stellar01 - just use a literal <tab> character (you can type one at your command prompt w/out the shell interfering like CTRL+V then <tab>). Alternatively - if your shell supports it - use $'s/...\t.../'. Or else: t=$(printf \\t); sed "s/...${t}.../" will also work.
    – mikeserv
    Commented Dec 30, 2015 at 20:07
1
sed 's/ [^ ]\{1,4\}/& /' <in >out

>1A    THIS ISATEST

It will work to insert a <space> after the longest match of the first occurrence of a sequence of 1 through 4 not-space characters immediately following a space character. This means that if the line starts with spaces it will affect the first not-space sequence (which is arguably correct behavior), or else if the second space-separated column consists of four or fewer characters it will append an additional space to that column (which is arguably incorrect behavior).

In no case does it substitute in a space for every fourth not-space character in the second column, though it does transform the example input to the example output.

0

With GNU awk

awk -F'\t' -vOFS='\t' '
  {patsplit($2, a, /.{4}/); 
   $2=""; for (k in a) $2=$2($2?"\t":"")a[k];  
   print}' file

Use patsplit to split the second field ($2) into 4 character chunks stored in array a. Join the chunks back with a tab separator and set into field 2 before printing out the record

1A    THIS  ISATEST
1B    THAT  ISATEST
4
  • What if you wanted to separate after more 4? Say like 90. Would I just have to add 90 dots? Commented Dec 30, 2015 at 17:40
  • @stellar01, take a look at my update
    – iruvar
    Commented Dec 30, 2015 at 17:40
  • I get an error: invalid -v option Commented Dec 30, 2015 at 17:47
  • @stellar01, you're probably using a very basic version of awk in that case
    – iruvar
    Commented Dec 30, 2015 at 18:10
0

With GNU awk you can use FPAT

awk '{$1=$1}1' OFS='\t' FPAT='>..\\s+\\w{4}|\\w*$'
  • expression >..\\s+\\w{4} match to >1A THIS and \\w*$ match to the rest of string.

  • $1=$1 forces to output string with new separator OFS

  • 1 is substitute for {print $0}

You must log in to answer this question.

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