3

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.

  • 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 Dec 30 '15 at 17:27
  • Does the awk solution I gave works for you ? – iamauser Dec 30 '15 at 18:00
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
    This worked perfectly. – cosmictypist Dec 30 '15 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.

  • For some reason I can't get this to work appropriately. – cosmictypist Dec 30 '15 at 17:39
  • The lines in my file actually start with a '>'. I will change my question – cosmictypist Dec 30 '15 at 17:41
  • There is no error, but I am not getting the desired split. The file looks that same as the input – cosmictypist Dec 30 '15 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 Dec 30 '15 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 Dec 30 '15 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
  • What if you wanted to separate after more 4? Say like 90. Would I just have to add 90 dots? – cosmictypist Dec 30 '15 at 17:40
  • @stellar01, take a look at my update – iruvar Dec 30 '15 at 17:40
  • I get an error: invalid -v option – cosmictypist Dec 30 '15 at 17:47
  • @stellar01, you're probably using a very basic version of awk in that case – iruvar Dec 30 '15 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}

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.