С недавним GNU tar
на ударе или полученной оболочке:
XZ_OPT=-9 tar cJf tarfile.tar.xz directory
нижний регистр tar j переключатель использует bzip, верхний регистр J переключатель использует xz.
XZ_OPT
переменная среды позволяет Вам установить xz
опции, которые не могут быть переданы с помощью вызывающих приложений такой как tar
.
Это теперь максимально.
Посмотрите man xz
для других опций можно установить (-e
/--extreme
мог бы принести Вам некоторую дополнительную пользу сжатия для некоторых наборов данных).
XZ_OPT=-e9 tar cJf tarfile.tar.xz directory
Если каналы в Вашей системе двунаправлены (как они находятся на Солярисе 11 и некоторый BSDs, по крайней мере, но не Linux):
cmd1 <&1 | cmd2 >&0
Остерегайтесь мертвых блокировок все же.
Также обратите внимание, что некоторые версии ksh93 в некоторых системах реализуют каналы (|
) использование пары сокета. пары сокета двунаправлены, но ksh93 явно закрывает обратное направление, таким образом, команда выше не работала бы с теми ksh93s даже в системах где каналы (как создано pipe(2)
системный вызов), двунаправлены.
Ну, его довольно "легкое" с именованными каналами (mkfifo
). Я поместил легкий в кавычки, потому что, если программы не разработаны для этого, мертвая блокировка вероятна.
mkfifo fifo0 fifo1
( prog1 > fifo0 < fifo1 ) &
( prog2 > fifo1 < fifo0 ) &
( exec 30<fifo0 31<fifo1 ) # write can't open until there is a reader
# and vice versa if we did it the other way
Теперь, там обычно буферизует включенный в письменной форме stdout. Так, например, если обе программы были:
#!/usr/bin/perl
use 5.010;
say 1;
print while (<>);
Вы ожидали бы бесконечный цикл. Но вместо этого, оба зашли бы в тупик; необходимо было бы добавить $| = 1
(или эквивалентный) для выключения выходной буферизации. Мертвая блокировка вызывается, потому что обе программы ожидают чего-то на stdin, но они не видят его, потому что его нахождение в stdout буфере другой программы, и еще не было записано в канал.
Обновление: слияние предложений от Stéphane Charzelas и Joost:
mkfifo fifo0 fifo1
prog1 > fifo0 < fifo1 &
prog2 < fifo0 > fifo1
делает то же, является короче, и более портативным.
prog1 < fifo | tee /dev/stderr | prog2 | tee /dev/stderr > fifo
.
– Andrey Vihrov
06.11.2012, 12:28
prog2 < fifo0 > fifo1
, можно избежать небольшого танца с exec 30< ...
(который между прочим только работы с bash
или yash
для fds более чем 10 как этот).
– Stéphane Chazelas
05.04.2014, 23:08
dash
кажется OK также (но ведет себя немного по-другому),
– derobert
09.11.2016, 19:27
Я не уверен, является ли это тем, что Вы пытаетесь сделать:
nc -l -p 8096 -c second &
nc -c first 127.0.0.1 8096 &
Это начинается путем открытия сокета слушания на порте 8096, и после того как соединение устанавливается, программа икры second
с stdin
как потоковый вывод и stdout
как потоковый ввод.
Затем секунда nc
запускается, который соединяется с портом прослушивания и порождает программу first
с stdout
как потоковый ввод и stdin
поскольку поток производится.
Это точно не сделано с помощью канала, но это, кажется, делает то, в чем Вы нуждаетесь.
Поскольку это использует сеть, это может быть сделано на 2 удаленных компьютерах. Это - почти путь веб-сервер (second
) и веб-браузер (first
) работа.
nc -U
для сокетов домена UNIX, которые только берут адресное пространство файловой системы.
– Ciro Santilli 新疆改造中心法轮功六四事件
30.05.2017, 08:51
Затем, когда вы соединяете их любым хорошим способом, вы должны увидеть на консоли:
dd if=/dev/sda bs=512 count=63 | hexdump -C
Удобным блоком для написания таких двунаправленных труб является то, что соединяет stdout и stdin текущего процесса вместе. Назовем это ioloop. После вызова этой функции вам нужно только запустить обычную трубу:
ioloop && # stdout -> stdin
cmd1 | cmd2 # stdin -> cmd1 -> cmd2 -> stdout (-> back to stdin)
Если вы не хотите изменять дескрипторы оболочки верхнего уровня, запустите ее в подоболочке:
( ioloop && cmd1 | cmd2 )
Вот портативная реализация ioloop с использованием именованной трубы:
ioloop() {
FIFO=$(mktemp -u /tmp/ioloop_$$_XXXXXX ) &&
trap "rm -f $FIFO" EXIT &&
mkfifo $FIFO &&
( : <$FIFO & ) && # avoid deadlock on opening pipe
exec >$FIFO <$FIFO
}
Именованная труба существует в файловой системе лишь ненадолго во время установки ioloop. Эта функция не совсем POSIX, потому что mktemp устарел (и потенциально уязвим для гоночных атак).
Возможна реализация, специфичная для linux, с использованием /proc/, которая не требует именованной трубы, но я думаю, что этой более чем достаточно.
Существует также
dpipe
, "двунаправленная труба", включенная в пакет vde2, и включенная в текущие системы управления пакетами дистрибутива .
dpipe processA = processB
socat, инструмент "все-все-все".
socat EXEC:Program1 EXEC:Program2
Поскольку @StéphaneChazelas правильно отмечает в комментариях, вышеприведенные примеры являются "базовой формой", в его ответе на похожий вопрос есть хорошие примеры с опциями.
bash
версии 4 имеет команду coproc
, которая позволяет сделать это в чистом bash
без именованных труб:
coproc cmd1
eval "exec cmd2 <&${COPROC[0]} >&${COPROC[1]}"
Некоторые другие оболочки также могут делать coproc
.
Ниже приведен более подробный ответ, но в цепочке три команды, а не две, что делает работу немного интереснее.
Если вы также используете cat
и stdbuf
, то конструкция может быть более понятной.
Версия, использующая bash
с cat
и stdbuf
, проста для понимания:
# start pipeline
coproc {
cmd1 | cmd2 | cmd3
}
# create command to reconnect STDOUT `cmd3` to STDIN of `cmd1`
endcmd="exec stdbuf -i0 -o0 /bin/cat <&${COPROC[0]} >&${COPROC[1]}"
# eval the command.
eval "${endcmd}"
Примечание, приходится использовать eval, потому что расширение переменной в <&$var незаконно в моей версии bash 4.2.25.
Версия, использующая чистый bash
:
Разбиваем на две части, запускаем первый конвейер под coproc, затем обедаем вторую часть (либо одна команда, либо конвейер), переподключая ее к первой:
coproc {
cmd 1 | cmd2
}
endcmd="exec cmd3 <&${COPROC[0]} >&${COPROC[1]}"
eval "${endcmd}"
Доказательство концепции:
файл ./prog
, просто фиктивная прога для потребления, маркировки и повторной печати строк. Использование под-оболочек для избежания проблем с буферизацией может быть излишеством, но это не суть важно.
#!/bin/bash
let c=0
sleep 2
[ "$1" == "1" ] && ( echo start )
while : ; do
line=$( head -1 )
echo "$1:${c} ${line}" 1>&2
sleep 2
( echo "$1:${c} ${line}" )
let c++
[ $c -eq 3 ] && exit
done
file ./start_cat
Это версия, использующая bash
, cat
и stdbuf
#!/bin/bash
echo starting first cmd>&2
coproc {
stdbuf -i0 -o0 ./prog 1 \
| stdbuf -i0 -o0 ./prog 2 \
| stdbuf -i0 -o0 ./prog 3
}
echo "Delaying remainer" 1>&2
sleep 5
cmd="exec stdbuf -i0 -o0 /bin/cat <&${COPROC[0]} >&${COPROC[1]}"
echo "Running: ${cmd}" >&2
eval "${cmd}"
или файл ./start_part
.
Это версия, использующая только чистый bash
.
Для демонстрационных целей я все еще использую stdbuf
, потому что ваша реальная программа в любом случае должна будет иметь дело с буферизацией внутри, чтобы избежать блокировки из-за буферизации.
#!/bin/bash
echo starting first cmd>&2
coproc {
stdbuf -i0 -o0 ./prog 1 \
| stdbuf -i0 -o0 ./prog 2
}
echo "Delaying remainer" 1>&2
sleep 5
cmd="exec stdbuf -i0 -o0 ./prog 3 <&${COPROC[0]} >&${COPROC[1]}"
echo "Running: ${cmd}" >&2
eval "${cmd}"
Output:
> ~/iolooptest$ ./start_part
starting first cmd
Delaying remainer
2:0 start
Running: exec stdbuf -i0 -o0 ./prog 3 <&63 >&60
3:0 2:0 start
1:0 3:0 2:0 start
2:1 1:0 3:0 2:0 start
3:1 2:1 1:0 3:0 2:0 start
1:1 3:1 2:1 1:0 3:0 2:0 start
2:2 1:1 3:1 2:1 1:0 3:0 2:0 start
3:2 2:2 1:1 3:1 2:1 1:0 3:0 2:0 start
1:2 3:2 2:2 1:1 3:1 2:1 1:0 3:0 2:0 start
Вот и все.