Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to identify a field in a line containing a string, and then move it to a different position. A line would look like this (sorry, I can't seem to type tabs in here)

string1 / string2 / blablaABCbla / string3

The idea is to locate the field containing ABC and move this field to the beginning or end of the line. How would I do this in bash, from stdout?

[edit]

I'm trying to work this into a piped sequence - I was hoping for a clever command I didn't know about, or else something really sed-ugly.

share|improve this question
1  
Why it's not possible to use for example python, as that makes it way simpler? –  Olli Feb 2 at 21:10
1  
@Olli - not everyone knows Python. The OP asked for the solution to be implemented using shell tools such as bash, awk, etc. You can write up an A if you feel Python would be the best option, but be sure to explain your rationale. If it's just b/c you know Python and not awk or bash then that's not a valid reason to write the solution up that way. On U&L those shell tools are the more typical way to solve most problems, but they are not the only ways. –  slm Feb 2 at 21:28

2 Answers 2

I use AWK (a standard UNIX/Linux command that there is even a Busybox implementation of) for a problem like that, e.g.

#!/bin/sh

awk -F'\t' 'BEGIN{srand()} {
    X=$0
    for(a=1;a<=NF;a++) {
        if($a ~ /ABC/) {
            if(rand() < .5) {
                X = $a " " $0 # Concat strings
            } else {
                X = $0 " " $a
            }
       }
   }
print X
}'

As an aside, I don't think the AWK solution is any more complicated than a Python one:

#!/usr/bin/env python

import random
import re
import sys

for line in sys.stdin:
        fields = re.split('\t',line[:-1])
        out = line[:-1]
        for field in fields:
                if re.search('ABC',field):
                        if random.randint(0,1) == 1:
                                out = field + " " + line[:-1]
                        else:
                                out = line[:-1] + " " + field
        print out
share|improve this answer

Manipulating a string in such a way as you've requested is a bit of work using just Bash. It's doable but I find using Perl to be much easier. This Perl one-liner will do what you want as well:

$ perl -a -F'\s*/\s*' -lne '
   printf "%s / ", grep( /ABC/, @F ); 
   printf "%s / %s / %s\n",  grep( !/ABC/, @F ); 
' file
blablaABCbla / string1 / string2 / string3

This solution assumes a 4 column formatted input, and that ABC will be present. You can reverse the order of the printf...grep... lines to get the ABC at the beginning (as shown) or at the end of the line. You'll need to make a couple of modifications like so:

$ perl -a -F'\s*/\s*' -lne '
   printf "%s / %s / %s / ",  grep( !/ABC/, @F ); 
   printf "%s\n", grep( /ABC/, @F );
' file 
string1 / string2 / string3 / blablaABCbla
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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