#linux #awk #sed
#linux #awk #sed
Вопрос:
У меня есть данные в этом формате (много таких строк):
TASK : Task 1
TASK : Task 2
TASK : Task 3
OWNER : Emp 1
OWNER : Emp 2
OWNER : Emp 3
Deadline : Monday
Deadline : Tuesday
Deadline : Wednesday
Это, я хочу преобразовать в:
TASK OWNER Deadline
Task 1 Emp 1 Monday
Task 2 Emp 2 Tuesday
Task 3 Emp 3 Wednesday
Даже если я смогу просто извлечь каждый столбец без имен заголовков столбцов, это было бы хорошо. После этого я могу добавить имена столбцов вручную.
Есть ли способ сделать это с помощью ‘awk’ или ‘sed’?
Комментарии:
1. Я не думаю, что ‘sed’ поможет вам далеко продвинуться, поскольку он анализирует документ построчно. Работа с несколькими строками — настоящая головная боль…
Ответ №1:
один из способов с awk:
awk -F': *' '{i=NR%3;i=i?i:3;a[i]=a[i]?a[i]"t"$2:$2}
END{for(x=1;x<=length(a);x )print a[x]}' file
он сохраняет порядок, опускает строку заголовка:
kent$ cat f
TASK : Task 1
TASK : Task 2
TASK : Task 3
OWNER : Emp 1
OWNER : Emp 2
OWNER : Emp 3
Deadline : Monday
Deadline : Tuesday
Deadline : Wednesday
kent$ awk -F': *' '{i=NR%3;i=i?i:3;a[i]=a[i]?a[i]"t"$2:$2}END{for(x=1;x<=length(a);x )print a[x]}' f
Task 1 Emp 1 Monday
Task 2 Emp 2 Tuesday
Task 3 Emp 3 Wednesday
объяснение
awk -F': *' #":any <space>" as FS
'{i=NR%3;i=i?i:3; #take NR%3 in i, if i=0, set i=3. because
#we want the i=0 case at the end of the output
a[i]=a[i]?a[i]"t"$2:$2}#concatenate the 2nd column to an array
END{for and print}' file#print the content of the array at the end
Заголовок
мы можем сохранить заголовок в переменной h
и распечатать его, прежде чем пройти a (array)
:
awk -F': *' '{...h=i==1?(h?h"t"$1:$1):h;a[i]=..}
END{print h;for...}' file
Комментарии:
1. Хорошая идея! Для заголовка вы можете прочитать файл дважды, чтобы при первом запуске вы сохранили все параметры:
-F: 'FNR==NR {a[$1]=$1; next}
, и т.д.2. @fedorqui это один из способов. на самом деле достаточно просмотреть файл один раз для head. просто возьмите и объедините
$1
whenNR%3==certain value(0 or 1 or 2)
3. Это блестяще. Я принял ваш ответ.. Если это не слишком сложно, не могли бы вы также добавить небольшое объяснение того, как это работает? Поможет мне в создании этих команд самостоятельно в будущем!
4. @sanjeevmk добавил объяснение и обработку заголовка. Обратите внимание, что
3
приведенные выше коды были жестко запрограммированы, но это может быть переменная. вы можете получить число с помощью других волшебных инструментов, таких какgrep, awk or your eyes ...
5. @Kent: Когда я запускаю это на 3.1.3, он говорит: «FNR = 9) fatal: попытка использовать массив `a’ в скалярном контексте» Есть идеи, почему?
Ответ №2:
Решение на Perl:
perl -le 'while (<>) {
chomp;
($h, $t) = split / : /;
$i , push @{$ar[0]}, $h if $h ne $ar[0][-1];
push @{$ar[$i]}, $t;
};
$" = "t";
print "@{$ar[0]}";
print join $", map shift @{$ar[$_]}, 1 .. $#ar while @{$ar[1]}'
Если вкладки плохо выравнивают текст, я бы использовал Text:: Table.
Ответ №3:
Вот относительно хорошая awk
версия:
BEGIN {FS=" : ";OFS="t"}
/^TASK/ {task [tpos ] = $2}
/^OWNER/ {owner[opos ] = $2}
/^Deadline/ {due [dpos ] = $2}
END {
print "TASK", "OWNER", "DEADLINE"
for (i in task) {
print task[i],owner[i],due[i]
}
}
🙂
Он сохраняет строку на блок, потому что ему не нужен gsub()
вызов, поскольку он использует в :
качестве разделителя. Сохраните его, скажем, test.awk
и выполните следующим образом:
awk -f test.awk input.txt
Обновить:
Приведенная выше команда приводит к невыровненному выводу в оболочке:
TASK OWNER DEADLINE
Task 1 Emp 1 Monday
Task 2 Emp 2 Tuesday
Task 3 Emp 3 Wednesday
Вы можете исправить это с помощью column
команды:
awk -f test.awk input.txt | column -t -s $'t'
Теперь вывод выглядит чистым:
TASK OWNER DEADLINE
Task 1 Emp 1 Monday
Task 2 Emp 2 Tuesday
Task 3 Emp 3 Wednesday
Комментарии:
1. Это намного приятнее, 1.
2. 😉 Имена ваших переменных стали чище, но я не хотел их копировать. Определенно лучше использовать описательные имена переменных при принятии решения о создании скрипта, а не использовать из него одну строку. Ваше и мое сочетание было бы «самым приятным»! 🙂
3. Нет, не беспокойтесь об этом, я бы предпочел удалить свой ответ и просто добавить полные переменные к вашим. Я не то чтобы одержим кодом, который я публикую здесь, он должен быть использован или «украден». Я добавил более длинные переменные и исправил несколько незначительных опечаток. Приветствия.