Используя TAC для чтения файла в обратном порядке
Я довольно новичок в кодировании UNIX, и у меня есть файл, который мне нужно прочитать в обратной строке за строкой. В файле есть разделы кода внутри {}. Затем мне нужно запустить скрипт awk с этим обращенным файлом в качестве входных данных. У меня есть служба поддержки, устанавливающая tac, но прежде, чем они это сделают, я хочу знать, будет ли он выводить то, что мне нужно, или кто-нибудь может предложить альтернативу.
Файл содержит данные в виде:
page 0 0 0 none
{
layer 0 0 0 "1line" 0 8 8 3
{
sector 0 -1 0 32
{
point_name 0 0 34543 34 44 1 1 0
status 1 0 1 0 1 431232 "transformer" 23 12
analog 1 0 1 0 1 321234 11.5 43 1 1 0
...
...
...
device 1 0 1 "ground" 32 56 1 1 0
}
}
}
и я хочу сохранить {}, но повернуть строки между {} так, чтобы результат был похож:
page 0 0 0 none
{
layer 0 0 0 "1line" 0 8 8 3
{
sector 0 -1 0 32
{
device 1 0 1 "ground" 32 56 1 1 0
...
...
...
analog 1 0 1 0 1 321234 11.5 43 1 1 0
status 1 0 1 0 1 431232 "transformer" 23 12
point_name 0 0 34543 34 44 1 1 0
}
}
}
Кроме того, TAC перезаписывает входной файл или сохраняет его как другой файл?
2 ответа
tac
просто меняет порядок строк в файле, поэтому вам нужно что-то более мощное, чтобы выполнить то, что вы хотите. Кроме того, все инструменты оболочки не включают средства перезаписи входного файла без использования временных файлов. Некоторые инструменты (например, sed
, Perl
и т. д.) имеют так называемую опцию "редактирование на месте", которая при отсутствии суффикса файла резервной копии дает чистый результат перезаписи файла.
Чтобы выполнить то, что вы хотите, я бы рекомендовал использовать awk
, Беги как:
awk -f script.awk file > newfile
Чтобы перезаписать ваш входной файл, используя временный файл, запустите:
awk -f script.awk file > temp && mv temp file
Содержание script.awk
:
/{/ {
print (a ? a ORS : "") $0
f=1; a=b=""
next
}
f && !/}/ {
a = (a ? a ORS : "") $0
b = $0 (b ? ORS b : "")
next
}
/}/ && b {
print b ORS $0
a=b=f=""
next
}1
Результаты:
page 0 0 0 none
{
layer 0 0 0 "1line" 0 8 8 3
{
sector 0 -1 0 32
{
device 1 0 1 "ground" 32 56 1 1 0
...
...
...
analog 1 0 1 0 1 321234 11.5 43 1 1 0
status 1 0 1 0 1 431232 "transformer" 23 12
point_name 0 0 34543 34 44 1 1 0
}
}
}
Кроме того, вот один вкладыш:
awk '/{/ { print (a ? a ORS : "") $0; f=1; a=b=""; next } f && !/}/ { a = (a ? a ORS : "") $0; b = $0 (b ? ORS b : ""); next } /}/ && b { print b ORS $0; a=b=f=""; next }1' file
Объяснение:
Первый блок кода спрашивает, содержит ли строка открывающую скобку. Если это так, выведите что-нибудь в записи "а", за которой следует текущая запись (строка, содержащая открывающую скобку). Установите флаг, удалите записи "a" и "b" и пропустите обработку остальной части кода.
Второй блок будет выполнен тогда и только тогда, когда установлен флаг и строка не содержит закрывающей скобки. Теперь мы создаем две записи 'a' и 'b'. Напомним, что запись "а" будет напечатана, если строка содержит открывающую скобку. Поэтому он должен быть построен в ориентации "от начала до конца". Затем мы создаем запись "b" в ориентации "конец к началу". Затем "next" пропускает обработку остальной части кода.
Третий блок будет выполнен, если строка содержит закрывающую скобку и запись "b" (напомним, что это построение записи в обратной ориентации). Затем мы печатаем запись "b", за которой следует текущая строка (строка с закрывающей скобкой). Удалите записи "a", "b" и сбросьте флаг. "Далее", чтобы пропустить обработку остальной части кода. "1" в конце включает печать по умолчанию.
Как и большинство инструментов UNIX (стиль) tac
не перезаписывает оригинальный файл и не записывает новый, он печатает в stdout
, чтобы написать новый файл с tac
вы бы использовали перенаправление tac file > newfile
это спасло бы обратное file
в newfile
, Вы не можете делать то, что вам нужно с tac
один, вам нужен сценарий.
Вот один в awk
:
{
# store each line in the array line
line[n++] = $0
}
/{/ {
# get the line number of the last line containing {
first=NR
}
!/}/ {
# get the line number of the last line not containing }
last=NR
}
END {
# print first section in order
for (i=0;i<first;i++)
print line[i]
# print second section in reverse order
for (i=last-1;i>=first;i--)
print line[i]
# print last section in order
for (i=last;i<NR;i++)
print line[i]
}
Сохраните это в файл скажем reverse
затем беги awk -f reverse file
:
$ awk -f reverse file
page 0 0 0 none
{
layer 0 0 0 "1line" 0 8 8 3
{
sector 0 -1 0 32
{
device 1 0 1 "ground" 32 56 1 1 0
...
...
...
analog 1 0 1 0 1 321234 11.5 43 1 1 0
status 1 0 1 0 1 431232 "transformer" 23 12
point_name 0 0 34543 34 44 1 1 0
}
}
}
Используйте перенаправление для создания нового файла awk -f reverse file > newfile
,