Поворот строк в текстовом файле за n шагов

#linux #unix #command-line #command

#linux #unix #командная строка #команда

Вопрос:

У меня есть текстовый файл с тысячами строк, и мне нужно повернуть строки. Вот пример:

myfile.txt :

 line1
line2
line3
line4
line5
line6
line7
  

Я хотел бы повернуть строки с n шагами. Например, если n = 2 . строка 1 перемещается в строку 3, строка 2 перемещается в строку 4, строка 3 перемещается в строку 5, … строка 6 перемещается в строку 1, строка 7 перемещается в строку 2. Таким образом, результат должен быть:

 line6
line7
line1
line2
line3
line4
line5
  

Может быть, я мог бы использовать Python и прочитать файл, повернуть список и сохранить в другой файл. Интересно, есть ли уже утилита командной строки для этой цели? он должен принимать имя файла и n в качестве аргументов и выводить повернутые строки в новый файл.

Я ценю вашу помощь.

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

1. Вы действительно хотите, чтобы строка 2 отображалась в результате дважды?

Ответ №1:

Используйте head и tail , а также некоторое простое арифметическое расширение bash. Вам также нужно либо tac , либо wc :

Сначала создайте минимально воспроизводимый пример для входного файла. Set n — количество строк от конца файла для поворота к началу:

 n = 2
perl -le 'print "line$_" for 1..7' > in_file
cat in_file
  

С принтами:

 line1
line2
line3
line4
line5
line6
line7
  

Способ 1: Поворот с помощью tail и head , плюс wc .

Это немного менее сложно, чем метод 2, и используется wc -l ... - $n для вычисления количества строк для head печати. Я предпочитаю этот метод, потому что намерения программиста здесь более ясны. Это также быстрее, смотрите тесты ниже.

 ( tail -n $n in_file ; head -n $(( $( wc -l <in_file ) - $n )) in_file ) > out_file
  

С принтами:

 line6
line7
line1
line2
line3
line4
line5
  

Способ 2: поворот с помощью tail и head , плюс tac .

Здесь,
tac : запишите строки в стандартном выводе в обратном порядке,
tail -n 3 : запишите вышеуказанные строки в обратном порядке, начиная со строки 3 с конца исходного файла (таким образом, строки 1-2 не записываются), tac : используйте tac всего два раза, чтобы изменить обратный порядок строк, чтобы записать строки в исходном порядке.

 ( tail -n $n in_file ; tac in_file | tail -n  $(( $n 1 )) | tac ) > out_file
  

Тесты:

Использование метода 1 wc значительно быстрее, чем использование метода 2 tac в два раза:

 perl -le 'print "line$_" for 1..1e7' > in_file
n=2
  
 for i in `seq 1 10` ; do
    ( time ( tail -n $n in_file ; head -n $(( $( wc -l <in_file ) - $n )) in_file ) > out_file ) 2>amp;1 | grep real
done
  

С принтами:

 real    0m0.539s
real    0m0.538s
real    0m0.545s
real    0m0.566s
real    0m0.540s
real    0m0.532s
real    0m0.561s
real    0m0.534s
real    0m0.530s
real    0m0.520s
  
 for i in `seq 1 10` ; do
    ( time ( tail -n $n in_file ; tac in_file | tail -n  $(( $n 1 )) | tac ) > out_file ) 2>amp;1 | grep real
done
  

С принтами:

 real    0m0.855s
real    0m0.884s
real    0m0.916s
real    0m0.829s
real    0m0.838s
real    0m0.873s
real    0m0.877s
real    0m0.862s
real    0m0.835s
real    0m0.867s
  

Я запустил это с помощью MacBook Pro с macOS v.10.14.6, запустив:

 bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)

  

Ответ №2:

немного подробно с awk, но..

 $ cat tst.awk
BEGIN {
  step=(!step)?2:step
}
{
  a[FNR step]=$0
  nr=FNR
}
END {
  for(i=nr 1; i in a;i  )
    a[(i%step) 1]=a[i]
  for(i=1; i<=nr ;i  )
          print a[i]
}
  
 $ awk -f tst.awk file
line6
line7
line1
line2
line3
line4
line5
  
 $ awk -v step=4 -f tst.awk file
line4
line5
line6
line7
line1
line2
line3
  

Ответ №3:

Вот метод, использующий tee команды управления заданиями wait и amp; и bash замену процессов, который, в отличие от ответов до сих пор, работает с каналами и перенаправлениями, поэтому имя файла нужно указать только один раз, или вместо этого можно использовать поток:

 N=2
tee >(tail -n $N amp;) 
    >(wait amp;amp; head -n -$N) > /dev/null < myfile.txt
  

Или с потоком вместо имени файла:

 N=2
seq -f 'line%g' 7 | 
tee >(tail -n $N amp;) 
    >(wait amp;amp; head -n -$N) > /dev/null
  

Вывод любого:

 line6
line7
line1
line2
line3
line4
line5
  

Ответ №4:

Вы можете сделать это с помощью команд оболочки head и tail . Если вы хотите «повернуть» файл длиной N 2 раза, вы должны напечатать последние N-2 строки файла, а затем первые 2 строки.

Приведенный ниже пример поворачивает файл с именем «rotate» на 5 строк 2 «раза».

 tail --lines 3 rotate
head --lines 2 rotate
  

или в виде однострочного tail --lines 3 rotate; head --lines 2 rotate

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

1. Вы пробовали это? это не дает ожидаемого результата. Что это за жестко заданные значения 3 и 2 ?

2. Странно, это дает мне ожидаемый результат. Какой результат вы получили? Я хотел первые 2 строки файла с 5 строками. Итак, я напечатал последние 3 строки (5-2), а затем первые 2.