4 Note on backreferences and POSIX
source | link

Semi-serious answer: it's not you, you are fine. The problem is totally in sed's s/// command's verbosity (compare this with the alternative answers):

$ echo "Hello some good world!" |
sed 's/\(^[^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+$\)/\3\2\1/'
world! some good Hello

We may also want to swap the first and the last words even if we have space characters before the first and/or after the latter (thanks to comments and other answers):

$ echo "  Hello some   good world!  " |
sed 's/^\([[:space:]]*\)\([^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+\)\([[:space:]]*\)$/\1\4\3\2\5/'
  world! some   good Hello  

However, these commands use some non-POSIX GNU extensions to the BRE - Basic Regular Expression - syntax (namely, + and |).
A (more portable) command that satisfies the POSIX standard while keeping the convenience of alternation (|) would require Extended regular expressions. For example, using GNU sed with the --posix option (which disables GNU extensions - not actually required):

$ echo "  Hello some   good world!  " |
sed --posix -E 's/^([[:space:]]*)([^[:space:]]{1,})([[:space:]].*[[:space:]]|[[:space:]]{1,})([^[:space:]]{1,})([[:space:]]*)$/\1\4\3\2\5/'
  world! some   good Hello  

Note, however, that POSIX ERE syntax does not include backreferences. This command, too, will require an implementation with extensions to succeed.

Semi-serious answer: it's not you, you are fine. The problem is totally in sed's s/// command's verbosity (compare this with the alternative answers):

$ echo "Hello some good world!" |
sed 's/\(^[^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+$\)/\3\2\1/'
world! some good Hello

We may also want to swap the first and the last words even if we have space characters before the first and/or after the latter (thanks to comments and other answers):

$ echo "  Hello some   good world!  " |
sed 's/^\([[:space:]]*\)\([^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+\)\([[:space:]]*\)$/\1\4\3\2\5/'
  world! some   good Hello  

However, these commands use some non-POSIX GNU extensions to the BRE - Basic Regular Expression - syntax (namely, + and |).
A (more portable) command that satisfies the POSIX standard while keeping the convenience of alternation (|) would require Extended regular expressions. For example, using GNU sed with the --posix option (which disables GNU extensions):

$ echo "  Hello some   good world!  " |
sed --posix -E 's/^([[:space:]]*)([^[:space:]]{1,})([[:space:]].*[[:space:]]|[[:space:]]{1,})([^[:space:]]{1,})([[:space:]]*)$/\1\4\3\2\5/'
  world! some   good Hello  

Semi-serious answer: it's not you, you are fine. The problem is totally in sed's s/// command's verbosity (compare this with the alternative answers):

$ echo "Hello some good world!" |
sed 's/\(^[^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+$\)/\3\2\1/'
world! some good Hello

We may also want to swap the first and the last words even if we have space characters before the first and/or after the latter (thanks to comments and other answers):

$ echo "  Hello some   good world!  " |
sed 's/^\([[:space:]]*\)\([^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+\)\([[:space:]]*\)$/\1\4\3\2\5/'
  world! some   good Hello  

However, these commands use some non-POSIX GNU extensions to the BRE - Basic Regular Expression - syntax (namely, + and |).
A (more portable) command that satisfies the POSIX standard while keeping the convenience of alternation (|) would require Extended regular expressions. For example, using GNU sed with the --posix option (which disables GNU extensions - not actually required):

$ echo "  Hello some   good world!  " |
sed --posix -E 's/^([[:space:]]*)([^[:space:]]{1,})([[:space:]].*[[:space:]]|[[:space:]]{1,})([^[:space:]]{1,})([[:space:]]*)$/\1\4\3\2\5/'
  world! some   good Hello  

Note, however, that POSIX ERE syntax does not include backreferences. This command, too, will require an implementation with extensions to succeed.

3 Minor clarification on GNU extensions
source | link

Semi-serious answer: it's not you, you are fine. The problem is totally in sed's s/// command's verbosity (compare this with the alternative answers):

$ echo "Hello some good world!" |
sed 's/\(^[^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+$\)/\3\2\1/'
world! some good Hello

We may also want to swap the first and the last words even if we have space characters before the first and/or after the latter (thanks to comments and other answers):

$ echo "  Hello some   good world!  " |
sed 's/^\([[:space:]]*\)\([^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+\)\([[:space:]]*\)$/\1\4\3\2\5/'
  world! some   good Hello  

However, these commands use some non-POSIX GNU extensions to the BRE - Basic Regular Expression - syntax (namely, + and |).
A (more portable) command that satisfies the POSIX standard while keeping the convenience of alternation (|) would require extendedExtended regular expressions. For example, using GNU sed with the --posix option (which disables GNU extensions):

$ echo "  Hello some   good world!  " |
sed --posix -E 's/^([[:space:]]*)([^[:space:]]{1,})([[:space:]].*[[:space:]]|[[:space:]]{1,})([^[:space:]]{1,})([[:space:]]*)$/\1\4\3\2\5/'
  world! some   good Hello  

Semi-serious answer: it's not you, you are fine. The problem is totally in sed's s/// command's verbosity (compare this with the alternative answers):

$ echo "Hello some good world!" |
sed 's/\(^[^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+$\)/\3\2\1/'
world! some good Hello

We may also want to swap the first and the last words even if we have space characters before the first and/or after the latter (thanks to comments and other answers):

$ echo "  Hello some   good world!  " |
sed 's/^\([[:space:]]*\)\([^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+\)\([[:space:]]*\)$/\1\4\3\2\5/'
  world! some   good Hello  

However, these commands use some non-POSIX GNU extensions (namely, + and |).
A (more portable) command that satisfies the POSIX standard while keeping the convenience of alternation (|) would require extended regular expressions. For example, using GNU sed with the --posix option (which disables GNU extensions):

$ echo "  Hello some   good world!  " |
sed --posix -E 's/^([[:space:]]*)([^[:space:]]{1,})([[:space:]].*[[:space:]]|[[:space:]]{1,})([^[:space:]]{1,})([[:space:]]*)$/\1\4\3\2\5/'
  world! some   good Hello  

Semi-serious answer: it's not you, you are fine. The problem is totally in sed's s/// command's verbosity (compare this with the alternative answers):

$ echo "Hello some good world!" |
sed 's/\(^[^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+$\)/\3\2\1/'
world! some good Hello

We may also want to swap the first and the last words even if we have space characters before the first and/or after the latter (thanks to comments and other answers):

$ echo "  Hello some   good world!  " |
sed 's/^\([[:space:]]*\)\([^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+\)\([[:space:]]*\)$/\1\4\3\2\5/'
  world! some   good Hello  

However, these commands use some non-POSIX GNU extensions to the BRE - Basic Regular Expression - syntax (namely, + and |).
A (more portable) command that satisfies the POSIX standard while keeping the convenience of alternation (|) would require Extended regular expressions. For example, using GNU sed with the --posix option (which disables GNU extensions):

$ echo "  Hello some   good world!  " |
sed --posix -E 's/^([[:space:]]*)([^[:space:]]{1,})([[:space:]].*[[:space:]]|[[:space:]]{1,})([^[:space:]]{1,})([[:space:]]*)$/\1\4\3\2\5/'
  world! some   good Hello  
2 Added commands for preserving spaces and portability
source | link

Semi-serious answer: it's not you, you are fine. The problem is totally in sed's s/// command's verbosity (compare this with the alternative answers):

$ echo "Hello some good world!" |
sed 's/\([^[^[^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+$\)/\3\2\1/'
world! some good Hello

We may also want to swap the first and the last words even if we have space characters before the first and/or after the latter (thanks to comments and other answers):

$ echo "  Hello some   good world!  " |
sed 's/^\([[:space:]]*\)\([^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+\)\([[:space:]]*\)$/\1\4\3\2\5/'
  world! some   good Hello  

However, these commands use some non-POSIX GNU extensions (namely, + and |).
A (more portable) command that satisfies the POSIX standard while keeping the convenience of alternation (|) would require extended regular expressions. For example, using GNU sed with the --posix option (which disables GNU extensions):

$ echo "  Hello some   good world!  " |
sed --posix -E 's/^([[:space:]]*)([^[:space:]]{1,})([[:space:]].*[[:space:]]|[[:space:]]{1,})([^[:space:]]{1,})([[:space:]]*)$/\1\4\3\2\5/'
  world! some   good Hello  

Semi-serious answer: it's not you, you are fine. The problem is totally in sed's s/// command's verbosity (compare this with the alternative answers):

$ echo "Hello some good world!" |
sed 's/\([^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+$\)/\3\2\1/'
world! some good Hello

Semi-serious answer: it's not you, you are fine. The problem is totally in sed's s/// command's verbosity (compare this with the alternative answers):

$ echo "Hello some good world!" |
sed 's/\(^[^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+$\)/\3\2\1/'
world! some good Hello

We may also want to swap the first and the last words even if we have space characters before the first and/or after the latter (thanks to comments and other answers):

$ echo "  Hello some   good world!  " |
sed 's/^\([[:space:]]*\)\([^[:space:]]\+\)\([[:space:]].*[[:space:]]\|[[:space:]]\+\)\([^[:space:]]\+\)\([[:space:]]*\)$/\1\4\3\2\5/'
  world! some   good Hello  

However, these commands use some non-POSIX GNU extensions (namely, + and |).
A (more portable) command that satisfies the POSIX standard while keeping the convenience of alternation (|) would require extended regular expressions. For example, using GNU sed with the --posix option (which disables GNU extensions):

$ echo "  Hello some   good world!  " |
sed --posix -E 's/^([[:space:]]*)([^[:space:]]{1,})([[:space:]].*[[:space:]]|[[:space:]]{1,})([^[:space:]]{1,})([[:space:]]*)$/\1\4\3\2\5/'
  world! some   good Hello  
1
source | link