#shell #awk #sed #posix #sh
#оболочка #awk #sed #posix #sh
Вопрос:
Новичок в StackExchange, простите меня за ошибки.
У меня есть входной файл, который необходимо скопировать в другой файл, до последнего символа.
inputfile.txt:
input {
"inputstuff"
}
filetowriteto.txt:
Stuff {
foo {
"foostuff"
}
bar {
"barstuff"
}
}
После запуска скрипта результирующий файл теперь должен быть:
filetowriteto.txt:
Stuff {
foo {
"foostuff"
}
bar {
"barstuff"
}
input {
"inputstuff"
}
}
В основном скрипт копирует input
набор строк и вставляет их непосредственно перед последней правой скобкой filetowriteto.txt
.
Скрипт не может полагаться на количество строк, поскольку filetowriteto.txt
не имеет предсказуемого количества строк foo или bar, и я не знаю, как использовать sed или awk для этого.
Ответ №1:
Попробуйте:
$ awk 'FNR==NR{ if (NR>1) print last; last=$0; next} {print " " $0} END{print last}' filetowriteto.txt inputfile.txt
Stuff {
foo {
"foostuff"
}
bar {
"barstuff"
}
input {
"inputstuff"
}
}
Чтобы изменить файл на месте:
awk 'FNR==NR{ if (NR>1) print last; last=$0; next} {print " " $0} END{print last}' filetowriteto.txt inputfile.txt >tmp amp;amp; mv tmp filetowriteto.txt
Как это работает
FNR==NR{ if (NR>1) print last; last=$0; next}
При чтении первого файла, (а) если мы находимся не в первой строке, выведите значение
last
, (б) присвоите текст текущей строкеlast
и (в) пропустите остальные команды и перейдите кnext
строке.При этом используется обычный трюк awk. Условие
FNR==NR
выполняется только тогда, когда мы читаем первый файл. Это потому, что в awk NR — это количество строк, которые мы прочитали до сих пор, в то время как FNR — это количество строк, которые мы прочитали до сих пор из текущего файла. Таким образом,FNR==NR
это верно только тогда, когда мы читаем из первого файла.print " " $0
При чтении второго файла выводите каждую строку с некоторым начальным пробелом.
END{print last}
После того, как мы закончили печать второго файла, выведите последнюю строку первого файла.
Ответ №2:
Учитывая:
$ cat /tmp/f1.txt
input {
"inputstuff"
}
$ cat /tmp/f2.txt
Stuff {
foo {
"foostuff"
}
bar {
"barstuff"
}
}
Для достижения этой цели можно использовать группировку команд:
$ ( sed '$d' f2.txt ; cat f1.txt ; tail -n1 f2.txt )
или (эта версия не создает вспомогательную оболочку)
$ { sed '$d' f2.txt ; cat f1.txt ; tail -n1 f2.txt; }
Как это работает?
sed '$d' f2.txt
печатает все, кроме последней строки f2.txtcat f1.txt
печатает f1.txt в этот моментtail -n1 f2.txt
теперь выведите последнюю строку f2
Если вы хотите сделать отступ f1.txt , используйте sed вместо cat. Вы также можете использовать sed для печати последней строки:
$ { sed '$d' /tmp/f2.txt ; sed 's/^/ /' /tmp/f1.txt ; sed -n '$p' /tmp/f2.txt; }
Stuff {
foo {
"foostuff"
}
bar {
"barstuff"
}
input {
"inputstuff"
}
}
И затем вы можете перенаправить вывод группировки в файл, если хотите, с >
помощью перенаправления.
Ответ №3:
$ cat tst.awk
NR==FNR {
rec = (NR>1 ? rec ORS : "") $0
next
}
FNR>1 {
print prev
if ( sub(/[^[:space:]].*/,"",prev) ) {
indent = prev
}
}
{ prev=$0 }
END {
gsub(ORS,ORS indent,rec)
print indent rec ORS prev
}
$ awk -f tst.awk inputfile.txt filetowriteto.txt
Stuff {
foo {
"foostuff"
}
bar {
"barstuff"
}
input {
"inputstuff"
}
}
В приведенном выше примере используется отступ от последней непустой строки перед последней строкой изменяемого файла, чтобы задать отступ для нового файла, который он вставляет.