2013-04-23 3 views
3

У меня есть текстовый файл, который содержит в каждой строке несколько слов, например:Сортировка каждая строка в текстовом файле

stackoverflow coding programming 
tag question badges 

я должен сортировать каждую строку и сохранить порядок строк. Например, для приведенного выше примера вывод должен быть:

coding programming stackoverflow 
badges question tag 

Мое решение до сих пор является создание временного файла, в котором сортируются все линии. Скрипт Баш выглядит следующим образом:

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

mv $FILE_TMP $FILE 

Он отлично работает, но я не доволен тем, что я должен создать дубликат файла, особенно потому, что файлы большие.

Итак, у меня вопрос, есть ли решение для сортировки каждой строки файла?

Спасибо,

+1

Достаточно UNIXish способ сделать это - не создавать временный файл, а вместо этого отправлять вывод на stdout. Тогда ваш маленький скрипт ведет себя так же, как «сортировка» и другие утилиты, и все счастливы. (И вы не создаете временный файл, если вам нужно выполнить другую обработку и отправить результат через канал ...) – fog

+0

Не удалось создать временную строку (массив символов), которая будет содержать содержимое строки (заканчивается символом конца строки), а затем сортировать их, а затем заменить текущую строку на новую отсортированную строку? Успех этого метода зависит от того, сможет ли u удалить конкретную строку из файла? Например, вы находитесь в строке # 1: - прочитайте его в строке >> sort it >> удалите строку # 1 из файла >> добавьте новую строку # 1 в файл >> перейдите к следующей строке и повторите. Если это возможно, вы можете избежать создания нового временного файла, если нет, то вам, возможно, придется прибегнуть к новому временному файлу. – Philo

ответ

3

Попробуйте это (Вы, возможно, придется изменить СЭД, если файл не через пробел):

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 

EDIT отметить, что это не на месте редактирования. Он действует как фильтр от stdin до stdout. Вы можете использовать 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()))) 
... 
Смежные вопросы