bash 使用 sed 反转输入顺序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13108503/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reverse input order with sed
提问by user1634254
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(使用 ++ 只是为了清楚起见)
采纳答案by F. Hauri
sedanswer
sed答案
As this question was tagged sed, my 1st answer was:
由于这个问题被标记为sed,我的第一个答案是:
First (using arbitraty _to mark viewed spaces, when a.txtcontain do to what:
首先(使用仲裁_来标记查看的空间,当a.txt包含do to what:
sed -e '
    :a;
    s/\([^_]*\) \([^ ]*\)/_/;
    ta;
    y/_/ /;
   ' a.txt
what to do
than, when a.txtcontain do to to what:
比,当a.txt包含do to to what:
sed -e '
    :a;
    s/^\(\|.* \)\([^+ ]\+\) \([+]*\)\(\| .*\)$/+/g;
    ta;
    :b;
    s/\([^_]*\) \([^ ]*\)/_/;
    tb;
    y/_/ /;
   ' <<<'do to to to what'
what to++ do
There is one +for each supressedduplicated word:
+每个被压制的重复词都有一个:
sed -e ':a;s/^\(\|.* \)\([^+ ]\+\) \([+]*\)\(\| .*\)$/+/g;ta;
        :b;s/\([^_]*\) \([^ ]*\)/_/;tb;
        y/_/ /;' <<<'do do to what what what what'
what+++ to do+
bashanswer
bash回答
But as there is a lot of people searching for simple bashsolutions, there is a simple way:
但是因为有很多人在寻找简单的bash解决方案,所以有一个简单的方法:
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 bashscripting:
甚至使用一些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
}
Will do:
会做:
revcnt <<<'do do to what what what what' 
what+++ to do+
Or as pure bash
或者作为纯粹的bash
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+
回答by Bernhard
I know taccan do something related
我知道tac可以做一些相关的事情
$ cat file
 do to what
$ tac -s' ' file
what to do  $
Where the -sdefines the separator, which is by default a newline.
其中-s定义了分隔符,默认情况下是换行符。
回答by Steve
I would use awkto 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
回答by potong
This might work for you (GNU sed):
这可能对你有用(GNU sed):
sed -r 'G;:a;s/^\n//;t;s/^(\S+|\s+)(.*)\n/\n/;ta' file
Explanation:
解释:
- Gadd a newline to the end of the pattern space (PS)
- :aloop name space
- s/^\n//;twhen the newline is at the front of the PS, remove it and print line
- s/^(\S+|\s+)(.*)\n/\2\n\1/;tainsert either a non-space or a space string directly after the newline and loop to- :a
- G在模式空间 (PS) 的末尾添加一个换行符
- :a循环命名空间
- s/^\n//;t当换行符在 PS 的前面时,将其删除并打印行
- s/^(\S+|\s+)(.*)\n/\2\n\1/;ta在换行符后直接插入一个非空格或空格字符串并循环到- :a
The -rswitch 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开关使正则表达式更容易理解(分组(...)、交替...|...和一个或多个的元字符+不再需要反斜杠前缀)。
回答by Vijay
May be you would like perl for this:
可能你会为此需要 perl:
perl -F -lane '@rev=reverse(@F);print "@rev"' your_file
回答by x-yuri
As Bernhard said, taccan 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.
我相信我的例子更有帮助。

