Копирование содержимого файла в другой файл в точке, расположенной относительно конца файла

#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; } 
 

Как это работает?

  1. sed '$d' f2.txt печатает все, кроме последней строки f2.txt
  2. cat f1.txt печатает f1.txt в этот момент
  3. 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"
       }
}
 

В приведенном выше примере используется отступ от последней непустой строки перед последней строкой изменяемого файла, чтобы задать отступ для нового файла, который он вставляет.