如何交换一行中的第一个单词和最后一个单词

如何交换一行中的第一个单词和最后一个单词

我试图使用 sed 命令 i= 将一行中的第一个单词替换为一行中的最后一个单词,但我似乎无法弄清楚。

答案1

使用awk

awk '{ t=$1; $1=$NF; $NF=t; print}'

这会:

  • t=$1- 设置t为第一个单词
  • $1=$NF- 将第一个单词设置为最后一个单词
  • $NF=t- 将最后一个单词设置为第一个单词
  • print- 打印新行。

$ echo 'one two three four five six' | awk '{ f=$1; l=$NF; $1=l; $NF=f; print}'
six two three four five one

答案2

使用 Perl,并假设空格分隔输入和空格分隔输出:

perl -ape '($F[0],$F[-1])=($F[-1],$F[0]);$_="@F\n"'

测试:

$ printf 'Cleanse Fold and Manipulate\n' | perl -ape '($F[0],$F[-1])=($F[-1],$F[0]);$_="@F\n"'
Manipulate Fold and Cleanse

Perl 代码用于-a将空格上的输入拆分到数组中@F,只需交换该数组开头和结尾的两个元素,然后用空格连接结果列表,并在末尾添加换行符。

一个较短的 Perl 变体,匹配第一个和最后一个单词并在替换中交换它们(这假设输入中没有侧翼空格):

perl -pe 's/^(\w*)(.*?)(\w*)$/$3$2$1/'

中间位 ,.*?非贪婪地匹配字符串的中间。我们无法轻松地做到这一点,因为之后sed没有像这样的非贪婪修饰符。?.*

答案3

半严肃的回答:不是你,你很好。问题完全在于sed命令s///的冗长(将其与替代答案进行比较):

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

我们可能还想交换第一个和最后一个单词,即使我们在第一个单词之前和/或后者之后有空格字符(感谢评论和其他答案):

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

但是,这些命令使用 BRE(基本正则表达式)语法的一些非 POSIX GNU 扩展(即+|)。
满足 POSIX 标准同时保持替换 ( ) 便利性的(更便携的)命令|将需要扩展正则表达式。例如,使用sed带有--posix选项的 GNU(这会禁用 GNU 扩展 - 实际上并不需要):

$ 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  

但请注意,POSIX ERE 语法不包括反向引用。该命令也需要具有扩展的实现才能成功。

相关内容