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

Linux 对文本文件中的每一行进行排序,linux,bash,Linux,Bash,我有一个文本文件,每行包含一些单词,例如: stackoverflow coding programming tag question badges 我必须对每行进行排序,并保持行的顺序。例如,对于上述示例,输出应为: coding programming stackoverflow badges question tag 到目前为止,我的解决方案是创建一个临时文件,其中所有行都被排序。 bash脚本如下所示: FILE_TMP=$FILE".tmp" while read line do

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

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
FILE\u TMP=$FILE.TMP”
读行时
做
echo$line | xargs-n1 | sort | xargs>>>$FILE_TMP
完成<$FILE
mv$文件\u TMP$文件
它工作得很好,但我不高兴我必须创建一个重复的文件,特别是因为文件很大

那么,我的问题是,有什么解决方案可以对文件的每一行进行适当排序


谢谢,

您可以编写一个文本编辑器(例如vim或emacs)来“就地”执行,但这并不能真正帮助您避免使用临时文件,因为文本编辑器将在内部使用临时文件


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

我认为以下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
提示$cat foo.awk
{
n=拆分($0,字)
做{
发生的更改\u=0
用于(idx=1;idx字[idx+1]){
t=单词[idx]
单词[idx]=单词[idx+1]
字[idx+1]=t
发生的更改=1
}
}
}时(发生更改!=0)
for(大写idx){
printf(“%s”,单词[idx])
}
拆分(“,数组)
打印“”
}
提示$awk-f foo.awk标记问题徽章
heredoc>EOF
编码编程堆栈溢出
徽章问号
编辑请注意,这不是就地编辑。它充当从标准输入到标准输出的过滤器。你也可以使用awk,但是在那里读写文件感觉很“笨拙”。如果您确实想避免使用临时文件,请使用类似Perl的方法。

实际上,任何解决此问题的“合理”解决方案都会将新内容写入新的临时文件,然后重命名。甚至像perl“就地”处理(
perl-pi…
)或文本编辑器这样的东西实际上也会这样做。如果您真的想就地执行,将数据写入相同的物理磁盘位置,可以这样做(新内容占用的空间与旧内容完全相同),但是

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

读行时
;do echo$line | xargs-n1 | sort | xargs;完成
这是相当脆弱的,例如,您应该绝对确保脚本的排序不会弄乱空白字符(DOS换行符呢?和连续空格呢?),脚本每行必须吐出相同数量(或更少)的字节。

试试这个(如果文件没有空格分隔,您可能必须更改sed):


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

接受的答案有点慢。请尝试以下方法:

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

awk'{split($0,a,”);asort(a);for(i=1;i)一种非常简单的方法是不创建临时文件,而是将输出发送到stdout。然后,您的小脚本的行为就像“sort”和其他实用程序一样,每个人都很高兴。(如果需要进行其他处理并通过管道发送输出,则不创建临时文件…)您不能创建一个临时“字符串”(字符数组)来接收行的内容(以行尾字符结尾)然后对它们进行排序,然后用新排序的行替换当前行?此方法的成功与否取决于您是否可以从文件中删除特定行?例如,假设您在第1行:-将其读入字符串>>对其排序>>从文件中删除第1行>>将新行添加到文件>>移动到下一行并重复。如果这是pos这样可以避免创建新的临时文件,如果不创建,则可能必须使用新的临时文件。
>>> import os
>>> import fileinput
>>> for line in fileinput.input('file.txt', inplace=1):
...     line = line.rstrip(os.linesep)
...     print(' '.join(sorted(line.split())))
...
awk ' {split( $0, a, " " ); asort( a ); for( i = 1; i <= length(a); i++ ) printf( "%s ", a[i] ); printf( "\n" ); }' input >output