Текстовое управление с sed

В настоящее время у меня есть несколько текстовых файлов с содержанием, бывшим похожим на это (со многими строками):

565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15

Я хочу изменить каждую строку, чтобы иметь следующий формат:

0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

Есть ли какой-либо способ сделать вышеупомянутое использование sed? Или я должен обратиться к Python?

12
задан 5 June 2017 в 12:26

5 ответов

Вы могли сделать это с sed, да, но другие инструменты более просты. Например:

$ awk '{
        printf "%s ", $2; 
        for(i=3;i<=NF;i++){
            printf "%s:%s:1 ",$1,$(i) 
        }
        print ""
       }' file 
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

Объяснение

awk разделит каждую строку входа на пробеле (по умолчанию), сохраняя каждого поля как $1, $2, $N. Так:

  • printf "%s ", $2; распечатает 2-е поле и конечный пробел.
  • for(i=3;i<=NF;i++){ printf "%s:%s:1 ",$1,$(i) } : выполнит итерации по полям 3 к последнему полю (NF количество полей), и для каждого из них оно распечатает 1-е поле, a :, затем текущее поле и a :1.
  • print "" : это просто печатает заключительную новую строку.

Или Perl:

$ perl -ane 'print "$F[1] "; print "$F[0]:$_:1 " for @F[2..$#F]; print "\n"' file 
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

Объяснение

-a делает perl ведите себя как awk и разделение его вход на пробеле. Здесь, поля хранятся в массиве @F, подразумевать, что 1-е поле будет $F[0], 2-е $F[1] и т.д. Так:

  • print "$F[1] " : распечатайте 2-е поле.
  • print "$F[0]:$_:1 " for @F[2..$#F]; : выполните итерации по полям 3 к последнему полю ($#F число элементов в массиве @F, так @F[2..$#F] берет часть массива, запускающуюся в 3-м элементе до конца массива), и распечатайте 1-е поле, a :, затем текущее поле и a :1.
  • print "\n" : это просто печатает заключительную новую строку.
22
ответ дан 5 June 2017 в 12:26

Ну, можно сделать это в sed, но работах Python также.

$ ./reformatfile.py  input.txt                                                                        
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

Содержание reformatfile.py как так:

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as fd:
    for line in fd:
        words = line.strip().split()
        pref = words[0]
        print(words[1],end=" ")
        new_words = [ ":".join([pref,i,"1"]) for i in words[2:] ]
        print(" ".join(new_words))

Как это работает? Нет действительно ничего особенно специального продолжения. Мы открываем первый параметр командной строки как файл для чтения и возобновляем разрушение каждой строки в "слова" или отдельные объекты. Первые слова становятся pref переменная, и мы печатаем на stdout секунде (слова [1]) объект, заканчивающийся пространством. Затем мы создаем новый набор "слов" через понимания списка и .join() функция во временном списке приставки, каждого слова и строки "1". Заключительный шаг должен распечатать их

5
ответ дан 5 June 2017 в 12:26

С awk:

awk '{printf "%s ",$2; for (i=3; i<=NF; i++) printf $1":"$i":1 "; printf "\n"}' file

или с ударом:

while read -r -a a; do                  # read line to array a
  printf "%s " ${a[1]}                  # print column #1
  for ((i=2;i<${#a[@]};i++)); do        # loop from column #2 to number of columns
    printf "%s " "${a[0]}:${a[$i]}:1"   # print content/values
  done
  echo                                  # print line break
done < file                             # read file from stdin

Вывод:

0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 
5
ответ дан 5 June 2017 в 22:26

С awk:

awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i);\
          printf("%s:%s:1\n", $1, $NF)}' file.txt

Это - все о форматировании разделенных пробелом полей в нужном формате:

  • printf("%s ", $2) печать второе поле с конечным пробелом

  • for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i) выполняет итерации по 3-му к предпоследним полям и печатает поля в нужном формате (первое поле, затем двоеточие, затем текущее поле, затем двоеточие, наконец 1) с конечным пробелом

  • printf("%s:%s:1\n", $1, $NF) печать последнее поле с новой строкой

Пример:

% cat file.txt
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15

% awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i); printf("%s:%s:1\n", $1, $NF)}' file.txt
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
0
ответ дан 5 June 2017 в 22:26

Вот ужасный путь sed!

$ sed -r 's/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/; :a s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /; t a; s/ $//' file
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

Больше четко:

sed -r '
s/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/
:a 
s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /
t a
s/ $//'

Примечания

  • -r использование ДО
  • s/old/new/ замена old с new
  • ^([0-9]+) сохраняет некоторые числа в начале строки
  • \1 обратная ссылка на первый сохраненный шаблон
  • :a маркировка этот раздел сценария a
  • ( |$) или пространство или конец строки
  • t тест, была ли последняя замена успешна - если это было, затем сделайте следующая команда
  • a находит маркировать :a и делает это снова
  • s/ $//, удаляют конечный пробел

Поэтому после добавления структуры к первой части, мы неоднократно находим последний экземпляр структуры и применяем его к следующему числу...

, Но я соглашаюсь, что другие инструменты помогают...

0
ответ дан 5 June 2017 в 22:26

Другие вопросы по тегам:

Похожие вопросы: