sed move pattern to beginning of line

Viewed 451

I have a textfile with lines of text where I want to move a pattern to the beginning of the line with sed. The pattern is the sequences like [35 of 44].

CSV files and Jupyter _ Even More Python for Beginners - Data Tools [35 of 44].description
Calling An API _ Python for Beginners [36 of 44].description

With \\[.*?\\] I can match this part [11 of 31] of the line, but I can't figure out how to move this pattern to the start of the line.

[35 of 44] CSV files and Jupyter _ Even More Python for Beginners - Data Tools.description
[36 of 44] Calling An API _ Python for Beginners.description

Hopefully, someone can help me!

3 Answers

You need to capture both what matches and what precedes it to do the replacement. In sed, the \(…\) captures what's in the … part. Hence:

sed -e 's/\(.*\)\(\[[^]]*\]\)/\2\1/'

Using single quotes on the command line avoids needing to use doubled-up backslashes.

As shown, this generates:

[35 of 44]CSV files and Jupyter _ Even More Python for Beginners - Data Tools .description
[36 of 44]Calling An API _ Python for Beginners .description

If you want a space after the [n of m] information, add it:

sed -e 's/\(.*\)\(\[[^]]*\]\)/\2 \1/'

Note that if there are two or more [n of m] sequences on the line, only the last one will be moved. Also, the search does not enforce that the material between the square brackets is of the form [1 of 2] (number of number). It would be possible to do so; it is not clear that it is worth worrying about it.

With your shown samples, please try following.

awk '
match($0,/\[[^]]*\]/){
  print substr($0,RSTART,RLENGTH),substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)
}
' Input_file

Explanation: Using match function of awk to match from [ to till ] in each line then printing the matched text's sub string first followed by rest of the line's value.

You can use the following POSIX ERE based sed command:

sed -E 's/(.*[^[:space:]])[[:space:]]*(\[[0-9]+ of [0-9]+])/\2 \1/' file

Details:

  • -E - enables POSIX ERE syntax (less escaping)
  • (.*[^[:space:]]) - Group 1: any text and then a non-whitespace char
  • [[:space:]]* - zero or more whitespace
  • (\[[0-9]+ of [0-9]+]) - Group 2: [, one or more digits, space, of, space, one or more digits, ].

The replacement is \2 \1, that is, Group 1 value, space, Group 2 value.

See the online demo:

s='CSV files and Jupyter _ Even More Python for Beginners - Data Tools [35 of 44].description
Calling An API _ Python for Beginners [36 of 44].description'
sed -E 's/(.*[^[:space:]])[[:space:]]*(\[[0-9]+ of [0-9]+])/\2 \1/' <<< "$s"

Output:

[35 of 44] CSV files and Jupyter _ Even More Python for Beginners - Data Tools.description
[36 of 44] Calling An API _ Python for Beginners.description
Related