2016-07-19 6 views
1

Мне нужен сценарий оболочки, предназначенный для печати строк в шаблоне из трех файлов.bash script Требуемые строки из нескольких файлов bash

file1.txt, file2.txt,file3.txt 

Мне нужен выход, чтобы быть

line1 of file1.txt 
line2 of file1.txt 
line1 of file2.txt 
line2 of file2.txt 
line1 of file3.txt 
line2 of file3.txt 
line3 of file1.txt 
line4 of file1.txt 
line3 of file2.txt 
line4 of file2.txt 
line3 of file3.txt 
line4 of file3.txt 

... 

Как мы можем получить это в сценарий оболочки? Также он должен печатать только непустые строки.

+0

Насколько велики эти файлы? Было бы разумно поместить их в память и прорваться по линиям? –

+0

У всех файлов одинаковое количество строк? Если нет, что должно произойти, когда мы достигнем номера строки, которого нет в каждом файле? – Aaron

+0

@TomFenech: Да, но у меня нет идеи о длине файлов. – anudeep

ответ

2

Как насчет следующего сценария, который принимает файлы в качестве параметров:

TOTAL_LINES=$(wc -l < "$1") 
for n in $(seq 1 2 $TOTAL_LINES); do 
    for file in "[email protected]"; do 
    sed -n "$n{p;n;p}" $file 
    done 
done 

Я рассмотрел все файлы имели одинаковое количество строк, как это было предложено в комментариях, но он также будет работать, если это не в случае, если вы передали самый длинный файл в качестве первого параметра.

Небольшое пояснение по части сценария вы менее вероятно, чтобы узнать:

  • seq будет генерировать последовательность чисел for будет перебирать. Это синтаксис seq from increment upTo и используется вместо {from..upTo..increment} синтаксиса, который не принимает переменные
  • [email protected] представляет собой массив параметров, передаваемых в скрипт
  • sed -n "$n{p;n;p}" является sed команда, которая не будет отображаться текст по умолчанию, но будет выполнять p, n и p снова для линии $n; p печатает текущую строку, n переходит к следующей строке
1

Это не может быть наиболее эффективным подходом, но это будет работать, при условии, что у вас есть все ваши файлы в $ файлах и $ total_lines содержит число строк в каждом файле:

for line in $(seq 1 $total_lines) 
do 
    for file in $files 
    do 
     sed '/^$/d' $file | sed $line'!d' 
    done 
done 

sed '/^$/d' удаляет все пустые строки из потока; «! D»

СЭД $ строка выводит строку, соответствующую $ линии

+0

Хотя это не было указано явно, Я думаю, что OP хочет отображать строки два на два, как в его примере вывода. – Aaron

3

Perl на помощь:

perl -e 'open $FH[ @FH ], "<", $_ or die $! for @ARGV; 
     while (grep !eof $_, @FH) { 
      for my $fh (@FH) { 
       print scalar <$fh> for 1, 2; 
      } 
     }' -- file*.txt 

Она хранит все файлы, открытые в то же время (массив @FH содержит дескрипторы файлов). Хотя хотя бы один из них еще не закончился, он печатает две строки из каждой.

2

Рассмотрим четыре одинаковых входных файлов:

$ cat file1.txt 
line1 of file1.txt 
line2 of file1.txt 
line3 of file1.txt 
line4 of file1.txt 

Мы создаем printer.sh следующим образом:

#!/bin/bash 
LINES=2 # Configure this to set the number of consecutive lines per file 

MAX_HANDLE=3 
# Create descriptors 3,4,... for filename1,filename2.... 
for var in "[email protected]" 
do 
     eval exec "$MAX_HANDLE"'<"$var"' 
     ((MAX_HANDLE++)) 
done 

# Start infinite loop 
while : 
do 
    # First descriptor is 3 
    COUNTER=3 

    # Loop over all open file descriptors from 3 to MAX_HANDLE - 1 
    while [ $COUNTER -lt $MAX_HANDLE ]; do 
    # Read $LINES lines from the open file descriptor 
    LINE_COUNTER=0 
    while [ $LINE_COUNTER -lt $LINES ]; do 
     read -r line <&"$COUNTER" || DONE=true 
     if [[ "$DONE" = true ]]; then 
     exit 
     fi 


     # Print the line that was read 
     echo "$line" 
     ((LINE_COUNTER++)) 
    done 
    ((COUNTER++)) 
    done 
done 

Исполняя это входные параметры каждого добавляются в новую ручку и читать $LINES линии на (в этом случае по 2 строки за раз). Это работает только для файлов с одинаковой длиной, таких как OP.

$ ./printer.sh file1.txt file2.txt file3.txt file4.txt 
line1 of file1.txt 
line2 of file1.txt 
line1 of file2.txt 
line2 of file2.txt 
line1 of file3.txt 
line2 of file3.txt 
line1 of file4.txt 
line2 of file4.txt 
line3 of file1.txt 
line4 of file1.txt 
line3 of file2.txt 
line4 of file2.txt 
line3 of file3.txt 
line4 of file3.txt 
line3 of file4.txt 
line4 of file4.txt 
+0

, если строка1 файла1 пуста, мне не нужно печатать эту строку, а не идти вперед и проверять строку2 файла1, если это тоже пусто, перейдите к файлу2 и повторите то же самое до файла3. Как мы можем это сделать? – anudeep

+0

Я отредактировал чек, чтобы сделать то, о чем вы просили. Теперь он читается до EOF @ deps. – Jedi

1

Использование пасты и awk.

$ cat test.sh 
paste -d '|' file* | awk -F\| '{ 
    if(NR % 2 == 1) { 
     file1 = $1; 
     file2 = $2; 
     file3 = $3; 
    } else { 
     file1 = file1 "\n" $1; 
     file2 = file2 "\n" $2; 
     file3 = file3 "\n" $3; 
     print file1; 
     print file2; 
     print file3; 
    } 
}' 

Поскольку все файлы имеют одинаковую длину, мы можем сначала вставлять все файлы и печатать, когда номер строки является четным.

2

Вы можете использовать paste с awk, чтобы получить результат:

paste -d $'\01' file[123].txt | 
awk -F '\01' 'NR%2{for (i=1; i<=NF; i++) a[i]=$i; next} 
    {for (i=1; i<=NF; i++) print a[i] ORS $i}' 

line1 of file1.txt 
line2 of file1.txt 
line1 of file2.txt 
line2 of file2.txt 
line1 of file3.txt 
line2 of file3.txt 
line3 of file1.txt 
line4 of file1.txt 
line3 of file2.txt 
line4 of file2.txt 
line3 of file3.txt 
line4 of file3.txt 
  • Использование paste мы создаем бок о бок control-A (ASCII 1) разделителями выходного
  • Использование awk с разделителем полей в control-A мы выводим 2 строки из каждой колонки
+0

не могли бы вы объяснить код? – anudeep

+0

Я добавил краткое объяснение. Я могу ответить на любой конкретный вопрос, который у вас есть. Если вы запустите файл 'paste -d $ '\ 01' [123] .txt | cat -vte' вы увидите вывод из 'paste', чтобы лучше понять следующую команду awk. – anubhava

+0

Как я могу обобщить этот оператор, предположим, что мне нужны 3 строки вместо 2 строк на файл и как я могу избежать печати, если строки содержат пустые строки ? Как и в случае, если строка1 файла1 пуста, мне не нужно печатать эту строку, а не идти вперед и проверять строку2 файла1, если это тоже пусто, перейдите к файлу2 и повторите то же самое до файла3 – anudeep

1

Если y НУ не против создания промежуточных/временных файлов, split(1) который является частью Coreutils каждого дистрибутива Linux может быть под рукой:

#!/bin/bash 

# Split files every 2 lines using a numeric suffix 
for f in file*.txt; do 
    split -d -l 2 "${f}" "${f}"split 
done 

# Reverse intermediate file names, so we can glob them in numeric order 
for f in file*split*; do 
    mv "${f}" "reversed$(echo ${f}|rev)" 
done 

cat reversed* && rm reversed* 
2

большим количеством ответов. Это один AWK

создавать тестовые файлы

for f in file{1,2,3}.txt; do rm $f; for n in {1,2,3,4}; do echo "line $n of file $f" >> $f; done; done 

и программы AWK

awk ' 
    FNR == 1 && NR>1 { 
     exit # exit after completing the first file 
    } 
    { 
     # print 2 lines from the first file 
     if (NF) print 
     getline; if (NF) print 
     # print 2 lines from each other file 
     for (i=2; i<ARGC; i++) { 
      getline < ARGV[i]; if (NF) print 
      getline < ARGV[i]; if (NF) print 
     } 
    } 
' file{1,2,3}.txt 

В if (NF) print линии исключить пустые строки, так как число пробельных полей, разделенных будет равен нулю.

line 1 of file file1.txt 
line 2 of file file1.txt 
line 1 of file file2.txt 
line 2 of file file2.txt 
line 1 of file file3.txt 
line 2 of file file3.txt 
line 3 of file file1.txt 
line 4 of file file1.txt 
line 3 of file file2.txt 
line 4 of file file2.txt 
line 3 of file file3.txt 
line 4 of file file3.txt 
+0

Можете ли вы предложить, как мы можем сделать то же самое в python? все файлы имеют одинаковую длину. Если строка1 файла1 пуста, мне не нужно печатать эту строку, а не идти вперед и проверять строку2 файла1, если это тоже пусто, перейдите к файлу2 и повторите то же самое до файла3. Можем ли мы обобщить количество строк для печати и номер спасибо! – anudeep

Смежные вопросы