В настоящее время у меня есть несколько текстовых файлов с содержанием, бывшим похожим на это (со многими строками):
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?
Вы могли сделать это с 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"
: это просто печатает заключительную новую строку.Ну, можно сделать это в 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"
. Заключительный шаг должен распечатать их
С 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
С 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
Вот ужасный путь 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/ $//
, удаляют конечный пробел Поэтому после добавления структуры к первой части, мы неоднократно находим последний экземпляр структуры и применяем его к следующему числу...
, Но я соглашаюсь, что другие инструменты помогают...