2013-04-23 60 views
3

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

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 

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

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

谢谢

+1

这样做的一种非常不友好的方式是不创建临时文件,而是将输出发送到标准输出。然后你的小脚本的行为就像“排序”和其他公用事业,每个人都很开心。 (如果需要进行其他处理并通过管道发送输出,则不需要创建临时文件...) – fog 2013-04-23 17:06:04

+0

难道你不能创建一个临时的'字符串'(字符数组)来获取行的内容(以行尾字符结尾),然后对它们进行排序,然后用新排序的行替换当前行?这种方法的成功取决于你是否可以从文件中删除特定的行?示例说你在线#1: - 将它读入一个字符串>>对它进行排序>>从文件中删除行#1 >>将新行#1添加到文件>>移动到下一行并重复。如果这是可能的,那么你可以避免创建一个新的临时文件,如果没有,那么你可能不得不求助于新的临时文件。 – Philo 2013-04-23 17:07:31

回答

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

你可以脚本文本编辑器(VIM或Emacs,例如)做“到位”,但不会真正帮助你避免使用临时文件,因为文本编辑器会内部使用临时文件。

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

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 

编辑注意,这不是一个到位编辑。它充当从标准输入到标准输出的过滤器。你也可以使用awk,但是读写文件会感觉“笨重”。如果你真的想避免临时文件,可以使用类似Perl的东西。

0

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

您可以编译this answer代码为overwrite可执行文件,然后运行 (警告:这是危险的,备份你的文件第一)

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

这是相当脆弱的,例如,您应该一定要确保脚本的排序不会与空白字符混淆(DOS换行符和连续空白怎么办?),脚本必须在每行中吐出相同数量(或更少)的字节。

1

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()))) 
...