对文本文件中的每一行进行排序

时间:2013-04-23 17:00:08

标签: linux bash

我有一个文本文件,每行包含一些单词,例如:

stackoverflow coding programming
tag question badges

我必须对每一行进行排序并保留行的顺序。例如,对于上面的示例,输出应为:

coding programming stackoverflow
badges question tag

到目前为止,我的解决方案是创建一个临时文件,其中所有行都已排序。 bash脚本如下所示:

FILE_TMP=$FILE".tmp" 
while read line
do
echo $line | xargs -n1 | sort | xargs >>$FILE_TMP
done < $FILE

mv $FILE_TMP $FILE

它工作正常,但我不高兴我必须创建一个重复的文件,特别是因为文件很大。

所以,我的问题是有没有解决方法来排序文件的每一行?

谢谢,

6 个答案:

答案 0 :(得分:3)

试试这个(如果文件没有空格分隔,你可能需要更改sed):

cat datafile.dat | while read line; do echo $line | sed 's/ /\n/g' | sort | gawk '{line=line " " $0} END {print line}' ; done

答案 1 :(得分:2)

如果Python是一个选项,使用fileinput模块的就地支持将非常容易

>>> import os
>>> import fileinput
>>> for line in fileinput.input('file.txt', inplace=1):
...     line = line.rstrip(os.linesep)
...     print(' '.join(sorted(line.split())))
...

答案 2 :(得分:1)

您可以编写文本编辑器(例如vim或emacs)来编写脚本&#34;就位#34;但是这不会真正帮助您避免使用临时文件,因为文本编辑器将在内部使用临时文件。

如果你真正的问题是它运行缓慢,那可能是因为它为源文件中的每一行产生了3个不同的进程。您可以通过使用像perl这样的脚本语言来解决这个问题,这种语言可以通过文件排序行而不会产生任何其他进程。您还有一个额外的输出文件。

答案 3 :(得分:1)

接受的答案有点慢。试试这个:

awk ' {split( $0, a, " " ); asort( a ); for( i = 1; i <= length(a); i++ ) printf( "%s ", a[i] ); printf( "\n" ); }' input >output

注意:你的awk必须是GNU,以便有asort()。

答案 4 :(得分:0)

我认为以下awk善良应该做的工作:

prompt$ cat foo.awk
{
    n = split($0, words)
    do {
        change_occured = 0
        for (idx = 1; idx <= n; ++idx) {
            if (words[idx] > words[idx + 1]) {
                t = words[idx]
                words[idx] = words[idx + 1]
                words[idx + 1] = t
                change_occured = 1
            }
        }
    } while (change_occured != 0)
    for (idx in words) {
        printf("%s ", words[idx])
    }
    split("", array)
    print ""
}
prompt$ awk -f foo.awk <<EOF
heredoc> stackoverflow coding programming
heredoc> tag question badges
heredoc> EOF
coding programming stackoverflow  
badges question tag

编辑请注意,这不是就地编辑。它充当从stdin到stdout的过滤器。您也可以使用awk,但读取和写入文件感觉“笨拙”。如果你真的想避开临时文件,请使用像Perl这样的东西。

答案 5 :(得分:0)

实际上,针对此问题的任何“合理”解决方案都会将新内容写入新的临时文件,然后重命名。甚至像perl“就地”处理(perl -pi...)或文本编辑器这样的事情实际上也是如此。如果你想真正到位,写入相同的物理磁盘位置,可以完成(新内容占用与旧版本完全相同的空间),但是it's rather painful。< / p>

您可以将代码从this answer编译为overwrite可执行文件,然后运行 (警告:这很危险,请先备份您的文件!)

while read line ; do echo $line | xargs -n1 | sort | xargs ; done < f | ./overwrite f

这是相当脆弱的,例如,您应该绝对确定执行脚本的排序不会弄乱空白字符(DOS换行符和连续空白?),脚本必须吐出相同的数量(或当它吃的时候每行的字节数。