我试图使用 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 语法不包括反向引用。该命令也需要具有扩展的实现才能成功。