Remi.b
Remi.b

Reputation: 18239

Sorting file lines per matching pattern

Input

Here is the file test.txt

this is row4 row4
row2 xxx row2
row11 // row11
row10 mmm row10
row8row8 fubar
row1row1
row6 and row6
row7 row7
row3row3
/row9 row9
row5  /row5

On each row, there is the indication of where the row should be placed. For example, the current row 9 contains the string "row3row3", this means that the row 9 should be placed at position 3. Each row contains exactly twice the indication of where the row should be placed and no two rows have the same index.

Expected Output

Here is the expected output on test2.txt

row1row1    
row2 xxx row2
row3row3
this is row4 row4
row5  /row5
row6 and row6
row7 row7
row8row8 fubar
/row9 row9
row10 mmm row10
row11 // row11

Can you help me to sort the file correclty?

What I tried

Here is my trial so far. I think I am not too far but there is a bug I fail to find.

# Get the rows indication
a=$(grep -o row[0-9]* test.txt | sed s/row//)
a=( $a )

# Remove the double indication
a2=()
for i in $(seq 1 ${#a[@]})
do
[ $(($i%2)) -ne 0 ] && a2+=(${a[i]})
done

# Loop through each row
for row in $(seq 1 ${#a2[@]})
do
    # Search for the row that should be placed at position $row
    for i in "${!a2[@]}"; do
        if [[ "${a2[$i]}" = "${row}" ]]
        then
            # Once the correct row was found, read it and print it on another file
            p=$(sed "${a2[$i]}q;d" test.txt)
            echo $p >> test2.txt
            break
        fi
    done 
done

Upvotes: 1

Views: 502

Answers (4)

dawg
dawg

Reputation: 104092

Perl solution:

perl -nle 'push @a, $_ ; 
 END{print join("\n", map  { $_->[0] }
 sort { $a->[1] <=> $b->[1] }
 map  { [$_, /(\d+)/] } @a)}' file

Upvotes: 0

karakfa
karakfa

Reputation: 67567

You can always follow decorate/sort/undecorate pattern

$ sed -r 's/.*row([0-9]+)/\1\t&/' rows | sort -n | cut -f2-

row1row1
row2 xxx row2
row3row3
this is row4 row4
row5  /row5
row6 and row6
row7 row7
row8row8 fubar
/row9 row9
row10 mmm row10
row11 // row11

Upvotes: 2

Cyrus
Cyrus

Reputation: 88969

Try this:

tr -c '0-9\n' ' ' <file | awk '{print $1}' | paste -d " " - file | sort -k1,1n | cut -d " " -f 2-

Upvotes: 1

anubhava
anubhava

Reputation: 786101

Using gnu awk you can do this in a single command:

awk -F '.*row' 'BEGIN {
   PROCINFO["sorted_in"] = "@ind_num_asc"
}
{
   a[$2] = $0
}
END {
   for(k in a)
      print a[k]
}' file
  • Using custom field separator .*row we extract the number after row for each line
  • Using that number as key we create an array a where value is full line
  • PROCINFO["sorted_in"] = "@ind_num_asc" is used to sort associative array in ascending numerical order of array index

Output:

row1row1
row2 xxx row2
row3row3
this is row4 row4
row5  /row5
row6 and row6
row7 row7
row8row8 fubar
/row9 row9
row10 mmm row10
row11 // row11

Upvotes: 3

Related Questions