unix 使用sed反转输入顺序

wh6knrhe  于 10个月前  发布在  Unix
关注(0)|答案(7)|浏览(104)

我有一个文件,让我们称之为'a.txt',这个文件包含以下文本行

do to what

字符串
我想知道SED命令是什么,它可以颠倒文本的顺序,使其看起来像这样

what to do


我需要做一些附加的吗?比如在to后面加上do
to ++ do(用++来表示清楚)

mzsu5hc0

mzsu5hc01#

我知道tac可以做一些相关的事情

$ cat file
 do to what
$ tac -s' ' file

what to do  $

字符串
其中-s定义分隔符,默认情况下是换行符。

5us2dqdw

5us2dqdw2#

我会使用awk来实现这一点:

awk '{ for (i=NF; i>=1; i--) printf (i!=1) ? $i OFS : $i "\n" }' file.txt

字符串
结果如下:

what to do

  • 编辑 *:

如果您需要一行程序来“就地”修改文件,请尝试:

{ rm file.txt && awk '{ for (i=NF; i>=1; i--) printf (i!=1) ? $i OFS : $i "\n" }' > file.txt; } < file.txt

bgtovc5b

bgtovc5b3#

sed答案

由于这个问题被标记为sed,我的第一个答案是:
首先(使用任意_标记已查看的空格,当a.txt包含do to what时:

sed -e '
    :a;
    s/\([^_]*\) \([^ ]*\)/\2_\1/;
    ta;
    y/_/ /;
   ' a.txt
what to do

字符串
那么,当a.txt包含do to to what时:

sed -e '
    :a;
    s/^\(\|.* \)\([^+ ]\+\) \2\([+]*\)\(\| .*\)$/\1\2\3+\4/g;
    ta;
    :b;
    s/\([^_]*\) \([^ ]*\)/\2_\1/;
    tb;
    y/_/ /;
   ' <<<'do to to to what'
what to++ do


每个 * suppressed * 重复的单词有一个+

sed -e ':a;s/^\(\|.* \)\([^+ ]\+\) \2\([+]*\)\(\| .*\)$/\1\2\3+\4/g;ta;
        :b;s/\([^_]*\) \([^ ]*\)/\2_\1/;tb;
        y/_/ /;' <<<'do do to what what what what'
what+++ to do+

bash答案

但是,由于有很多人在寻找简单的bash解决方案,因此有一个简单的方法:

xargs < <(uniq <(tac <(tr \  \\n <<<'do do to what what what what')))
what to do


这可以写成:

tr \  \\n <<<'do do to what what what what' | tac | uniq | xargs 
what to do


或者使用一些bash脚本:

revcnt () { 
    local wrd cnt plut out="";
    while read cnt wrd; do
        printf -v plus %$((cnt-1))s;
        out+=$wrd${plus// /+}\ ;
    done < <(uniq -c <(tac <(tr \  \\n )));
    echo $out
}


将执行:

revcnt <<<'do do to what what what what' 
what+++ to do+

pure bash

revcnt() { 
    local out i;
    for ((i=$#; i>0; i--))
    do
        [[ $out =~ ${!i}[+]*$ ]] && out+=+ || out+=\ ${!i};
    done;
    echo $out
}


其中提交的字符串必须作为参数提交:

revcnt do do to what what what what
what+++ to do+


或者如果需要处理 * 标准输入 *(或从文件):

revcnt() { 
    local out i arr;
    while read -a arr; do
        out=""
        for ((i=${#arr[@]}; i--; 1))
        do
            [[ $out =~ ${arr[i]}[+]*$ ]] && out+=+ || out+=\ ${arr[i]};
        done;
        echo $out;
    done
}


因此,您可以处理多行:

revcnt <<eof
do to what
do to to to what
do do to what what what what
eof
what to do
what to++ do
what+++ to do+

gab6jxml

gab6jxml4#

这可能对你有用(GNU sed):

sed -r 'G;:a;s/^\n//;t;s/^(\S+|\s+)(.*)\n/\2\n\1/;ta' file

字符串
说明:

  • G在模式空间的末尾添加换行符(PS)
  • :a循环名称空间
  • s/^\n//;t当换行符位于PS前面时,将其移除并打印行
  • s/^(\S+|\s+)(.*)\n/\2\n\1/;ta直接在换行符后面插入一个非空格或空格字符串并循环到:a

-r开关使regexp更容易看到(分组(...)、交替...|...和一个或多个+的元字符无需使用反斜杠前缀)。
备选方案:

sed -E 'G;:a;s/^(\S+)(\s*)(.*\n)/\3\2\1/;ta;s/.//' file


注意:要反转生产线,应采用上述解决方案:

sed -E 'G;:a;/^(.)(.*\n)/\2\1/;ta;s/.//' file

eeq64g8w

eeq64g8w5#

也许你会喜欢Perl:

perl -F -lane '@rev=reverse(@F);print "@rev"' your_file

字符串

liwlm1x9

liwlm1x96#

作为Bernhard saidtac可以在这里使用:

#!/usr/bin/env bash
set -eu
echo '1 2 3
2 3 4
3 4 5' | while IFS= read -r; do
    echo -n "$REPLY " | tac -s' '
    echo
done

$ ./1.sh
3 2 1 
4 3 2 
5 4 3

字符串
我认为我的例子更有帮助。

i2loujxw

i2loujxw7#

SED

当你知道你想要交换的确切单词时:

$ cat a.txt
do to what

$ sed -ri '/do.*what/ s/do/what/' a.txt

$ cat a.txt
what to what

$ sed -ri '/what.*what/ s/what$/do/' a.txt

$ cat a.txt
what to do

字符串
但是你必须确切地知道单词的位置、它们的环境、围绕着它们的词、它们是在句子/行的开头还是结尾等等。要使用的正确元字符将取决于该信息。

相关问题