Как использовать AWK для непрерывного вывода строк из файла

#linux #bash #shell #awk

#linux #удар #оболочка #awk #bash

Вопрос:

У меня есть файл с несколькими строками, и я хочу непрерывно выводить некоторые строки файла, например, в первый раз печатать со строки 1 по строку 5, в следующий раз печатать со строки 2 по строку 6 и так далее. Я считаю AWK очень полезной функцией, и я попытался написать код самостоятельно, но он просто ничего не выводит. Ниже приведен мой код

 #!/bin/bash
for n in `seq 1 3`
do
  N1=$n
  N2=$((n 4))
  awk -v n1="$N1" -v n2="$N2" 'NR == n1, NR == n2 {print $0}' my_file >> new_file
done
  

Например, у меня есть входной файл с именем my_file

 1 99 tut
2 24 bcc
3 32 los
4 33 rts
5 642 pac
6 23 caas
7 231 cdos
8 1 caee
9 78 cdsa
  

Затем я ожидаю, что выходной файл в виде

 1 99 tut
2 24 bcc
3 32 los
4 33 rts
5 642 pac
2 24 bcc
3 32 los
4 33 rts
5 642 pac
6 23 caas
3 32 los
4 33 rts
5 642 pac
6 23 caas
7 231 cdos
  

Комментарии:

1. Спасибо, что продемонстрировали свои усилия в виде кода. ИМХО, вы могли бы сделать это в одном awk самом. Не могли бы вы, пожалуйста, опубликовать образец вашего ввода и ожидаемого результата для лучшего понимания вопроса здесь, мы могли бы сделать это в одном awk (если возможно) тоже.

2. Привет @RavinderSingh13 Я просто редактирую это, надеюсь, теперь это понятнее. Спасибо.

3. Я попробовал ваш код, и вывод в new_file выглядит правильным.

4. @Barmar Я перешел на другой компьютер, и теперь мой код тоже работает. Спасибо за ваш комментарий, это напоминает мне, что проблема может быть связана с системой.

Ответ №1:

Не могли бы вы, пожалуйста, попробовать следующее, написанное и протестированное с показанными примерами в GNU awk . Где нужно указать все строки, которые необходимо напечатать в lines_from переменной, тогда есть переменная с именем till_lines , которая сообщает нам, сколько строк нам нужно напечатать из определенной строки (например,—> из 1-й строки также напечатать следующие 4 строки). С другой стороны, я протестировал код OP, и он отлично сработал для меня, он генерирует выходной файл с помощью new_file, поскольку вызов awk в цикле bash НЕ является хорошей практикой, поэтому добавляю это в качестве улучшения и здесь.

 awk -v lines_from="1,2,3" -v till_lines="4" '
BEGIN{
  num=split(lines_from,arr,",")
  for(i=1;i<=num;i  ){ line[arr[i]] }
}
FNR==NR{
  value[FNR]=$0
  next
}
(FNR in line){
  print value[FNR] > "output_file"
  j=""
  while(  j<=till_lines){ print value[FNR j] > "output_file" }
}
'  Input_file  Input_file
  

Когда я вижу содержимое output_file , я вижу следующее:

 cat output_file
1 99 tut
2 24 bcc
3 32 los
4 33 rts
5 642 pac
2 24 bcc
3 32 los
4 33 rts
5 642 pac
6 23 caas
3 32 los
4 33 rts
5 642 pac
6 23 caas
7 231 cdos
  

Объяснение: Добавляю подробное объяснение выше.

 awk -v lines_from="1,2,3" -v till_lines="4" '    ##Starting awk program from here and creating 2 variables lines_from and till_lines here, where lines_from will have all line numbers which one wants to print from. till_lines is the value till lines one has to print.
BEGIN{                                           ##Starting BEGIN section of this program from here.
  num=split(lines_from,arr,",")                  ##Splitting lines_from into arr with delimiter of , here.
  for(i=1;i<=num;i  ){                           ##Running a for loop from i=1 to till value of num here.
    line[arr[i]]                                 ##Creating array line with index of value of array arr with index of i here.
  }
}
FNR==NR{                                         ##Checking condition FNR==NR which will be TRUE when 1st time Input_file is being read.
  value[FNR]=$0                                  ##Creating value with index as FNR and its value is current line.
  next                                           ##next will skip all further statements from here.
}
(FNR in line){                                   ##Checking condition if current line number is coming in array then do following.
  print value[FNR] > "output_file"               ##Printing value with index of FNR into output_file
  j=""                                           ##Nullifying value of j here.
  while(  j<=till_lines){                        ##Running while loop from j=1 to till value of till_lines here.
    print value[FNR j] > "output_file"           ##Printing value of array value with index of FNR j and print output into output_file
  }
}
'  Input_file Input_file                         ##Mentioning Input_file names here.
  

Комментарии:

1. @RavinderSingh13 Спасибо за ваши усилия, я решил свою проблему, перейдя на другой компьютер, похоже, что виновата система. Ваш сценарий и комментарии очень познавательны, спасибо.

2. @witt. S, ваше приветствие, ИМХО хотел бы поставить здесь точку. Честно говоря, вам следует избегать использования for цикла и последующего вызова awk внутри него. Вызов awk на каждой итерации цикла for является излишним, ИМХО, если возможно, вы могли бы использовать это единственное решение. приветствия.

Ответ №2:

Другой awk вариант

 awk '
BEGIN {N1=1; N2=5}
arr[NR]=$0 {}
END {
    while (arr[N2]) {
        for (i=N1; i<=N2; i  )
            print arr[i] 
        N1  
        N2  
    }
}
' file