Многократное использование данных канала для различных команд

Расширьте ответ:

  1. Если Вы хотите установить его глобальный, добавить set ts=2 к Вашему ~/.vimrc - если это не существует, просто создайте новый.

  2. Если Вы хотите установить позицию табуляции для определенного файла, используйте волшебную строку режима в энергии. Давайте возьмем файл C++ в качестве примера, добавим строку ниже в начале или конце файла: // vim: set ts=2

Читайте больше о modeline в энергии.

7
23.07.2013, 01:05
2 ответа

Можно использовать tee для дублирования команды для обработки целого потока многими, управляйте:

( ( seq 1 10 | tee /dev/fd/5 | sed s/^/line..\ / >&4 ) 5>&1 | wc -l ) 4>&1 
line.. 1
line.. 2
line.. 3
line.. 4
line.. 5
line.. 6
line.. 7
line.. 8
line.. 9
line.. 10
10

или разделение линию за линией, с помощью удара:

while read line ;do
    echo cmd1 $line
    read line && echo cmd2 $line
    read line && echo cmd3 $line
  done < <(seq 1 10)
cmd1 1
cmd2 2
cmd3 3
cmd1 4
cmd2 5
cmd3 6
cmd1 7
cmd2 8
cmd3 9
cmd1 10

Finaly там является путем к выполнению cmd1, cmd2 и cmd3 только однажды с 1/3 потока как STDIN:

( ( ( seq 1 10 |
         tee /dev/fd/5 /dev/fd/6 |
           sed -ne '1{:a;p;N;N;N;s/^.*\n//;ta;}' |
           cmd1 >&4
     ) 5>&1 |
       sed -ne '2{:a;p;N;N;N;s/^.*\n//;ta;}' |
       cmd2 >&4
  ) 6>&1 |
    sed -ne '3{:a;p;N;N;N;s/^.*\n//;ta;}' |
    cmd3 >&4
) 4>&1 
command_1: 1
command_1: 4
command_1: 7
command_1: 10
Command-2: 2
Command-2: 5
Command-2: 8
command 3: 3
command 3: 6
command 3: 9

Для попытки этого Вы могли использовать:

alias cmd1='sed -e "s/^/command_1: /"' \
    cmd2='sed -e "s/^/Command_2: /"' \
    cmd3='sed -e "s/^/Command_3: /"'

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

(
    for ((i=(RANDOM&7);i--;));do
        read line;
        echo CMD1 $line
      done
    for ((i=RANDOM&7;i--;));do
        read line
        echo CMD2 $line
      done
    while read line ;do
        echo CMD3 $line
      done
)
CMD1 1
CMD1 2
CMD1 3
CMD2 4
CMD2 5
CMD2 6
CMD2 7
CMD2 8
CMD2 9
CMD3 10

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

Иначе мог быть должен гарантировать, что каждый сценарий ничего не произведет к STDOUT, чем добавляют a cat в конце каждого сценария, чтобы смочь объединить их в цепочку:

#!/bin/sh

for ((i=1;1<n;i++));do
   read line
   pRoCeSS the $line
   echo >output_log
 done

cat

Заключительная команда могла быть похожей:

seq 1 10 | cmd1 | cmd2 | cmd2
3
27.01.2020, 20:19
  • 1
    я не думаю, что это отвечает, что OP пытается сделать. Идея для последовательных команд каждому, используют часть того же потока канала, каждый берущий точно где предыдущий брошенный. –  jw013 22.07.2013, 23:29
  • 2
    То, чего я пытаюсь достигнуть, несколько отличается Вашего сценария. Я хотел бы, например, cmd1 обработку первых 10 строк, cmd2 обработка следующих 15 строк, и так далее. Cmd1, cmd2, и т.д. являются функциями удара, и эти функции решают количество строк, которые будут обработаны согласно входу. –  arnaldocan 22.07.2013, 23:42
  • 3
    @arnaldocan хорошо, я думаю, справедливо понимают потребность, посмотрите демонстрационный сценарий и в последний раз управляйте образцом. –  F. Hauri 23.07.2013, 00:09
  • 4
    я думаю четвертый пример, решает проблему. Там какой-либо путь состоит в том, чтобы избегать использования "чтения" из-за своих ограничений скорости на большие файлы? –  arnaldocan 23.07.2013, 00:12
  • 5
    Можно использовать mapfile -n $numLines arraOfLines –  F. Hauri 23.07.2013, 00:46

Для head -n 10 чтобы смочь считать 10 строк и ни один больше символа от канала на stdin, это должно было бы считать один символ за один раз, чтобы не быть считанным ничто после последнего символа новой строки. Это было бы неэффективно.

Это что read встроенная оболочка делает, когда stdin не seekable.

{
  head -n 10 > /dev/null
  cat
} < myfile

Работы, потому что head читает блок данных и lseeks назад к сразу после конца 10-й строки. Это, очевидно, не может быть сделано с каналами.

На недавнем GNU или системах FreeBSD, некоторые приложения то использование stdio может быть сказан считать их вход один символ за один раз при помощи stdbuf -i1 или stdbuf -i0.

Однако это не работает с GNU head. Это работает с GNU sed хотя, таким образом, Вы могли сделать:

seq 20 | {
  stdbuf -i0 sed -n 10q
  cat
}

С другой стороны, то, что Вы могли сделать, управлять тем, что идет на канал так, чтобы была когда-либо самое большее только одна строка в нем за один раз.

Например, на Linux, Вы могли сделать:

one_line_at_a_time() {
  perl -MTime::HiRes=usleep -pe '
    BEGIN{$|=1;open F, "<", "/dev/fd/1"; $r=""; vec($r,fileno(F),1) = 1}
    usleep(1000) while select($ro=$r,undef,undef,0)'
}
seq 20 | one_line_at_a_time | { head -n 10 > /dev/null; cat; }

Это perl сценарий открывает "/dev/fd/1" в режиме чтения, который на Linux заставляет другой конец канала, подключенного к fd 1 (stdout) быть открытым. Тот путь, с select, это может проверить, существует ли что-то в канале (и сон, пока это не было освобождено) прежде, чем отправить следующую строку.

Конечно, это также ужасно неэффективно.

2
27.01.2020, 20:19

Теги

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