简体   繁体   English

使用 sed 反转输入顺序

[英]Reverse input order with sed

I have a file, lets call it 'a.txt' and this file contains the following text line我有一个文件,我们称之为“a.txt”,该文件包含以下文本行

do to what

I'm wondering what the SED command is to reverse the order of this text to make it look like我想知道 SED 命令是什么来反转文本的顺序以使其看起来像

what to do

Do I have to do some sort of append?我必须做某种附加吗? Like append 'do' to 'to' so it would look like就像将“do”附加到“to”一样,它看起来像

to ++ do (used ++ just to make it clear) to ++ do(使用 ++ 只是为了清楚起见)

I know tac can do something related我知道tac可以做一些相关的事情

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

what to do  $

Where the -s defines the separator, which is by default a newline.其中-s定义分隔符,默认情况下是换行符。

I would use awk to do this:我会使用awk来做到这一点:

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

Results:结果:

what to do

EDIT :编辑

If you require a one-liner to modify your file "in-place", try:如果您需要单线来“就地”修改您的文件,请尝试:

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

answer 答案

As this question was tagged , my 1st answer was:由于这个问题被标记为 ,我的第一个答案是:

First (using arbitraty _ to mark viewed spaces, when a.txt contain do to what :首先(使用仲裁_标记查看的空间,当a.txt包含do to what

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

than, when a.txt contain do to to what :比,当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

There is one + for each supressed duplicated word:每个被压制的重复词都有一个+

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+

answer 答案

But as there is a lot of people searching for simple solutions, there is a simple way:但是因为有很多人在寻找简单的解决方案,所以有一个简单的方法:

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

this could be written:这可以写成:

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

or even with some scripting:甚至使用一些脚本:

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
}

Will do:会做:

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

Or as pure 或者作为纯粹的

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

where submited string have to be submitted as argument:其中提交的字符串必须作为参数提交:

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

Or if prossessing standard input (or from file) is required:或者,如果需要处理标准输入(或来自文件):

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
}

So you can process multiple lines:所以你可以处理多行:

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+

This might work for you (GNU sed):这可能对你有用(GNU sed):

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

Explanation:解释:

  • G add a newline to the end of the pattern space (PS) G在模式空间的末尾添加一个换行符 (PS)
  • :a loop name space :a循环命名空间
  • s/^\\n//;t when the newline is at the front of the PS, remove it and print line s/^\\n//;t当换行在 PS 前面时,去掉并打印 line
  • s/^(\\S+|\\s+)(.*)\\n/\\2\\n\\1/;ta insert either a non-space or a space string directly after the newline and loop to :a s/^(\\S+|\\s+)(.*)\\n/\\2\\n\\1/;ta在换行符后直接插入非空格或空格字符串并循环到:a

The -r switch makes the regexp easier-on-the-eye (grouping (...) , alternation ...|... and the metacharacter for one-or-more + are relieved of the need of a backslash prefix). -r开关使正则表达式更容易理解(分组(...) 、交替...|...和一个或多个+的元字符不再需要反斜杠前缀) .

Alternative:选择:

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

NB To reverse the line, adapt the above solution to:注意要反转线,请将上述解决方案调整为:

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

可能你会为此想要 perl:

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

As Bernhard said , tac can be used here:正如伯恩哈德所说tac可以在这里使用:

#!/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 

I believe my example is more helpful.我相信我的例子更有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM