смотреть без пустой строки

Это определенно возможно, но неприятно. На самом деле, вы хотели бы пойти по-другому в отношении вещей.

Для этих конкретных файлов и этой задачи этот сценарий, вероятно, является самым простым и использует один цикл whileвместо любогоfor:

цикла.

exec 3

Он имеет фиксированную структуру из трех -столбцов для каждого файла и просто считывает их все сразу. file2открывается в файловом дескрипторе 3 (exec 3), так что вы можете читать его независимо от того,file1:то, что вы написали, открывает файл и читает первую строку только каждый раз. Команды readпомещают первое слово в x1, второе в x2и остальную часть строки в `x3.

Нет встроенного -или достаточно простого способа "сжать" два списка вместе или написать параллельный цикл for. Циклы for для чего-либо, кроме простых массивов или списков буквальных слов, сложны или невозможны, и создание правильного массива требует больше усилий, чем выполнение задачи другим способом.


Если у вас есть переменное количество столбцов, это сложнее, но мы можем использоватьmapfileдля создания массивов из строк, а затем обычную обработку массива с помощью цикла C -стиля forдля каждой строки:

while read line1 && read line2 <&3
do
    mapfile -d $'\t' a1 <<<"$line1"
    mapfile -d $'\t' a2 <<<"$line2"
    for ((i=0; i<${#a1[@]}; i++))
    do
        echo $((a1[i] - a2[i]))
    done
done 

При этом создаются два массива a1и a2, содержащие вкладку -, разделенные элементами каждой строки , и выполняется цикл до длины строки из file1(, игнорируя любые дополнительные элементы из другого файла ).

Наилучшее обобщенное приближение чего-то вроде zip, предполагая, что файлы правильно -сформированы и количество столбцов совпадает в соответствующих строках,будет что-то вроде while read a b... done < <(paste <(printf '%s\n' $(, что является абсолютной мерзостью.


Тем не менее, сценарии оболочки не являются хорошим механизмом для такого рода обработки , и awk -или даже лучше, правильный язык -был бы гораздо более подходящим и менее хрупким, чем этот.

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

0
06.10.2020, 16:29
2 ответа

Немного запутанно, но можно:

yes 'date -Is' | pv -qlL1 | sh

(также имеет то преимущество, что команда выполняется каждую секунду, а не каждые 2 секунды плюс время, необходимое для ее выполнения)

1выше — скорость в количестве строк в секунду и может быть только целым числом. Таким образом, 1 в секунду - это самое медленное, что вы можете получить. Вы можете отказаться от -l, хотя в этом случае скорость будет в количестве байтов в секунду. Таким образом, при 9 байтах на строку это будет одна команда каждые 9 секунд.

2
18.03.2021, 22:59
perl -e '$t=shift; while(1){print $o=$n if ($n=qx(@ARGV)) ne $o; sleep $t}' 1 date -Is
2020-10-07T06:49:07+03:00
2020-10-07T06:49:08+03:00
2020-10-07T06:49:09+03:00
2020-10-07T06:49:10+03:00

Улучшенная версия, которая выполняет дробные задержки и правильно обрабатывает пробелы и специальные символы в команде и аргументах:

#! /usr/bin/perl
use Time::HiRes qw(sleep);
die "usage: $0 delay cmd [args...]\n" if @ARGV < 2;
sub slurpcmd {
   open my $h, '-|', @_ or die "open $_[0]|: $!";
   local $/ unless wantarray;
   <$h>
}
my $t = shift; my ($o, $n);
while(1){print $o=$n if ($n=slurpcmd @ARGV) ne $o; sleep $t}

Добавление опций для форматирования вывода команды (красивое разделение, если многострочный и т. д. )оставлено читателю в качестве упражнения;-)

1
18.03.2021, 22:59

Теги

Похожие вопросы