Как “объединить” строки, распечатанные несколькими программами безопасно?

Как я говорю, какие данные (что формат данных) находятся в файле?
→ Используйте file утилита.

Здесь, Вы хотите знать формат данных в файле устройств, таким образом, необходимо передать -s флаг для сообщения file не только, чтобы сказать, что это - файл устройств, но и смотрит на содержание. Иногда Вам будет нужно -L отметьте также, если имя файла устройств является символьной ссылкой. Вы будете видеть вывод как это:

# file -sL /dev/sd*
/dev/sda1: Linux rev 1.0 ext4 filesystem data, UUID=63fa0104-4aab-4dc8-a50d-e2c1bf0fb188 (extents) (large files) (huge files)
/dev/sdb1: Linux rev 1.0 ext2 filesystem data, UUID=b3c82023-78e1-4ad4-b6e0-62355b272166
/dev/sdb2: Linux/i386 swap file (new style), version 1 (4K pages), size 4194303 pages, no label, UUID=3f64308c-19db-4da5-a9a0-db4d7defb80f

Учитывая этот демонстрационный вывод, первый диск имеет один раздел, и второй диск имеет два раздела. /dev/sda1 ext4 файловая система, /dev/sdb1 ext2 файловая система, и /dev/sdb2 некоторая область подкачки (приблизительно 4 ГБ).

Необходимо выполнить эту команду как корень, потому что обычные пользователи не могут считать разделы диска непосредственно: в случае необходимости добавить sudo впереди.

11
10.02.2014, 19:46
5 ответов

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

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

Например:

((./script1 | while read line1; do echo $line1; done) & \
(./script2 | while read line2; do echo $line2; done)) | doSomethingWithOutput
0
27.01.2020, 19:59
  • 1
    Не красивый. Вряд ли то надежное. Вряд ли та производительность будет хороша. –  Vi. 29.11.2013, 19:12
  • 2
    истории, Вы правы. Это не красиво, но больше походит на грязный взлом. Однако я не думаю, что этого достаточно для оценки производительности и надежности. Кроме того, Вы хотели использовать 'стандартные инструменты'. Таким образом, я не был бы удивлен, если необходимо принять некоторое уродство (в конце). Но возможно у кого-то есть более удовлетворительное решение. –  xwst 30.11.2013, 02:18
  • 3
    В настоящее время, я удовлетворен своей программой (связанный в вопросе) за исключением того, что это не доступно в репозиториях таким образом, нельзя считать даже небольшим "стандартом". Решение может быть к попытке продвинуть его там... –  Vi. 30.11.2013, 03:21

Вы могли сделать именованный канал с mkfifo, выведите весь вывод в именованный канал и отдельно читайте из именованного канала для Ваших собранных данных:

mkfifo /tmp/mypipe
job1 > /tmp/mypipe &
job2 > /tmp/mypipe &
job3 > /tmp/mypipe &

cat /tmp/mypipe > /path/to/final_output &

wait; wait; wait; wait
0
27.01.2020, 19:59
  • 1
    Как это защитит от искажения когда job1 и job2 вывод долго (> 4 096 байтов) строки? Это, кажется, именованный канал, эквивалентный из самого кода первый пример в quesion. –  Vi. 20.12.2013, 22:40
  • 2
    Очень справедливое замечание. Я не полагал, что большой блоб произвел несмотря на него вызываемый явно в Вашем вопросе. Я теперь задаюсь вопросом, нет ли, возможно, некоторого инструмента, который делает реверс tee, который походит точно, что Вы хотите. Возможно посмотрите на внутренности syslog или другие инструменты входа, потому что они определенно совокупный вывод от нескольких мест в один файл журнала. Блокировка может быть правильным ответом, как @emmanual предложенный, также. –  DopeGhoti 21.12.2013, 00:18

Решение, реализовывая блокировки:

function putlines () {
   read line || return $?
   while ! ln -s $$ lock >/dev/null 2>&1
   do
      sleep 0.05
   done
   echo "$line" 
}

function getlines () {
     while read lline
     do 
          echo "$lline"
          rm lock
     done
}

# your paralelized jobs  
(  
   job1 | putlines & 
   job2 | putlines & 
   job3 | putlines & 
   wait
) | getlines| final_processing

Должен быть более быстрый способ создать блокировку, чем использование файловой системы.

1
27.01.2020, 19:59

GNU Parallel.

С [115594]release notes[115595] от августа 2013:

c---rw---- 1 root lp 6, 0 2011-06-26 22:47 /dev/lp0

--line-буфер[115989] будет буферизировать вывод на линейной основе. [115990]-группа[115991] хранит вывод вместе для всего задания. [115992]-группа[115993] позволяет вывод смешивать с пол-линии, и пол-линии, идущей от одной работы, и пол-линии, идущей от другой. Работа. [115994] --line-буфер [115995] подходит между этими двумя; он печатает полную линию, но позволит смешивать строки различных заданий.

sudo chmod 666 /dev/lp0

Например:

echo "Y helo thar" > /dev/lp0

параллельный --line-буфер

Где [115600]jobs[115601] содержит:


short.sh[115603]:

long. sh[115605]:

Выход:

enter image description here

3
27.01.2020, 19:59

Старый вопрос, я знаю, Но я задавался вопросом о том же, и вот что я придумал:

garbling_job | (
    while read LINE
    do
        echo $LINE
    done
) &

Кажется, я могу запустить довольно много из них, не беспокоясь об искаженном выводе.

РЕДАКТИРОВАТЬ :Как предлагает Оле -Вы должны быть осторожны с длинными строками (> 4k, подробнее см. комментарий Олеся ниже)

Вот моя тестовая программа

if [ "$1" = "go" ]
then
for i in 1 2
do
    printf 111112222222222223333
    sleep.01
    printf 3333333444444444444555555555555
    sleep.01
    printf 6666666666666667777
    sleep.01
    printf 777777788888888889999999999999999
    sleep.01
    echo
done
exit
fi

# running them in sequence is all very fine
for i in 1 2 3 4 5 6 7 8
do
    echo bash $0 go 
done

# now this is all garbled up
for i in 1 2 3 4 5 6 7 8
do
    bash $0 go &
done
for i in 1 2 3 4 5 6 7 8; do wait; done

# using cat inbetween does not make it better
for i in 1 2 3 4 5 6 7 8
do
    bash $0 go | cat &
done
for i in 1 2 3 4 5 6 7 8; do wait; done

# it does not help to use stdbuff after the thing that just printfs sporadicall
for i in 1 2 3 4 5 6 7 8
do
    bash $0 go | stdbuf -oL cat &
done
for i in 1 2 3 4 5 6 7 8; do wait; done

# it does not help to use stdbuff before either - or I am not understanding stdbuff
for i in 1 2 3 4 5 6 7 8
do
    stdbuf -o10000 bash $0 go | stdbuf -oL cat &
echo
done
for i in 1 2 3 4 5 6 7 8; do wait; done

# can I read - yes - they are now fine again
for i in 1 2 3 4 5 6 7 8
do
bash $0 go | (
    while read LINE
    do
        echo $LINE
    done
) &
echo
done
for i in 1 2 3 4 5 6 7 8; do wait; done
0
12.04.2020, 14:15

Теги

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