Вставьте новые строки с отсутствующими значениями (NA)

Я хотел бы вставить новые строки в текстовые файлы, если отсутствуют значения. У меня есть, например, следующий текстовый файл (A.txt), для которого отсутствует строка 5. Кроме того, поскольку файл должен иметь 12 строк, строки 11-12 также отсутствуют.

1 2.30 2 3.01 3 3.22 4 3.34 6 3.01 7 2.90 8 2.99 9 3.00 10 3.02 

Мой ожидаемый результат следующий. Для отсутствующих случаев следует добавить строку с номером и NA. Как вы видите, это произошло по желанию в строках 5, 11 и 12:

 1 2.30 2 3.01 3 3.22 4 3.34 5 NA 6 3.01 7 2.90 8 2.99 9 3.00 10 3.02 11 NA 12 NA 

Я могу сделать это, используя следующий скрипт:

 f1=/my-directory/ echo "new file" > "$f1"/newfile.txt for i in {1..12}; do l=$(awk '{print $1}' /"$f1"/A.txt | grep -wE ^$i /"$f1"/A.txt) if grep --quiet -wE ^$i /"$f1"/A.txt; then echo "$l" >> "$f1"/newfile.txt; else echo "$i NA" >> "$f1"/newfile.txt; fi done 

Это прекрасно работает. Проблема в том, что мне нужно сделать это примерно для 600 файлов, содержащих более 160000 строк. Таким образом, решение цикла потребует слишком много времени для поиска по всем линиям. Мой вопрос: есть ли более простое решение, которое может это сделать?

5 Solutions collect form web for “Вставьте новые строки с отсутствующими значениями (NA)”

Вы можете сделать это с помощью awk скрипта:

 awk '{ while (NR + shift < $1) { print (NR + shift) " NA"; shift++ }; print } END { shift++; while (NR + shift < 13) { print (NR + shift) " NA"; shift++ } }' /tmp/test1 

будет выдавать требуемый результат для /tmp/test1 (замените это на каждый файл, который вы хотите обработать).

В более читаемой форме:

 #!/usr/bin/awk -f { while (NR + shift < $1) { print (NR + shift) " NA" shift++ } print } END { shift++ while (NR + shift < 13) { print (NR + shift) " NA" shift++ } } 

Сохраните это как файл, скажем, fill-missing , сделайте его исполняемым, тогда вы можете просто запустить

 ./fill-missing /tmp/test1 

Скрипт обрабатывает каждую строку, отслеживая ожидаемую дельта с текущим номером строки в shift . Поэтому для каждой строки, если текущая строка не соответствует первому номеру в строке, она печатает соответствующий номер строки, а затем NA и увеличивает дельта; как только номера строк совпадают, он печатает текущую строку. В конце процесса он печатает любые недостающие строки, необходимые для достижения 12.

здесь хорошо работает:

 join -a 1 -o 0,2.2 -e NA <(seq 12) A.txt 2>/dev/null 

Я выбрасываю stderr, потому что join жалуется, если поле объединения не лексически отсортировано.

файл awk

 BEGIN { i=1 ; } function upto(x) { while (i<x) printf "%d NA\n",i++ ;} { if ( $1 == i ) print ; upto($1) ; i++ ;} END { upto(final+1) ;} 

называться

 awk -f nl.awk -v final=12 /tmp/test1 

весь цикл

 cd /my/directory ls | while read f do awk -f ~/nl.awk -v final=12 $f > /an/other/dir/$f done 

где

  • вы помещаете awk-программу в свой файл $ HOME ( ~/nl.awk )

Вы также можете попробовать Python:

 #!/usr/bin/env python2 with open('file.txt') as f: check = 0 for line in f: if int(line.split()[0]) == check + 1: check = int(line.split()[0]) print line.rstrip() else: check = int(line.split()[0]) print int(line.split()[0]) - 1, 'NA' print line.rstrip() print int(line.split()[0]) + 1, 'NA' print int(line.split()[0]) + 2, 'NA' 

Здесь мы сравниваем номер строки int(line.split()[0]) с check + 1 , мы установили начальное значение check как 0 . Если значения равны, мы напечатали линию, иначе мы напечатали желаемый контент, т. Е. Номер нужной строки и NA . Последние две строки используются для печати 11-й и 12-й строк.

Glenn Jackman's bash и метод join с несколькими настройками, эта функция получает счет из входного файла и использует это значение как значение по умолчанию:

 # Usage: inlwmv file [ missing_value [ extra_lines ] ] # if unset, missing_value="NA", and extra_lines=0 inlwmv() { join -a 1 -o 0,2.2 -e "${2:-NA}" \ <(seq $((${3:-0} + $(tail -n 1 "$1" | cut -d ' ' -f1))) | sort -k 1b,1) \ <(sort -k 1b,1 "$1") | \ sort -g ; } 

Для вопроса ОП:

 inlwmv A.file "" 2 

Для этого дублированного вопроса версия Jackman терпит неудачу при последнем значении файла , ( join довольно тонкое в отношении порядка, но использование sort три раза заставляет его вести себя по мере необходимости):

 inlwmv afile 0 
  • Катить все файлы в папке, включая имя файла, используя цикл for?
  • Как я могу отображать 3 строки текста за один раз на 1 строку?
  • Добавление строки в файл из удаленного ssh
  • Заменить шаблон в файле с шаблоном во втором файле
  • Объединить вывод сценария в тело письма и отправить его как одно электронное письмо?
  • Как выбрать последнее число в строке в сценарии bash
  • Использование регулярных выражений для поиска списка слов. Поиск двух букв вместо 3. Почему?
  • Как подсчитать вхождения каждого слова, принадлежащего файлу, во все количество файлов `n`, переданных в качестве аргументов?
  • Как захватить содержимое строки до определенной строки?
  • Добавить столбцы в текстовый файл с заданным интервалом в Bash
  • Поиск файла для числа, которое находится между двумя конкретными номерами
  • Как «grep» для длины строки * not * в заданном диапазоне?
  • Linux и Unix - лучшая ОС в мире.