2013-08-01 2 views
4

Я хочу запустить 2 команды на входе в канал и хочу напечатать (на stdout) вывод обоих.Shell - Труба для нескольких команд в файле

Каждая команда представляет собой комбинацию grep, sed и awk.

Обе эти команды должны находиться в одном файле .sh.

Примеры команд:

cat mult_comm.sh  
sed 's/World/Boy/g'|grep Boy ; grep World 

# Input 
cat input.log 
Hello World 

# This command HAS to work EXACTLY like this 
cat input.log | bash mult_comm.sh 

Ожидаемый выход

Hello Boy 
Hello World 

Фактический выход

Hello Boy 

Я попытался с помощью тройника

cat mult_comm.sh 
tee >(sed 's/World/Boy/g'|grep Boy) | grep World 

Но это дает только

Hello World 

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

Это похоже на OS X/Linux: pipe into two processes? и Pipe output to two different commands, но я не могу понять, как использовать именованные каналы внутри скрипта.

+0

ли это обман, чтобы сделать это только с СЭД? 'sed -n 'h; s/World/Boy/g;/Boy/p; x;/World/p' pilcrow

ответ

11

При выполнении

tee >(some_command) 

Баш создает подоболочку для запуска some_command. Подстрока stdin назначается половине считывания. bash оставляет имя этого канала в командной строке, так что tee будет перекачивать свой вход в трубу. Подсвечники stdout и stderr остаются неизменными, поэтому они все те же, что и tee.

Таким образом, при выполнении

tee >(some_command) | some_other_command 

Теперь Баш первым создает процесс для запуска tee, и присваивает его stdout к пишущей половине трубы, а другой процесс запустить some_other_command с его stdin назначены на половину считывания той же трубы. Затем он создает другой процесс для запуска some_command, как указано выше, присваивая его stdin считывающей половине другого канала и оставляя его stdout и stderr без изменений. Однако stdout уже перенаправлен на some_other_command, и это то, что наследует some_command.

В вашем конкретном примере,

tee >(sed 's/World/Boy/g'|grep Boy) | grep World 

мы в конечном итоге с:

    --> sed 's/World/Boy/g' --> grep Boy -- 
       /          \ 
input --> tee --<           \ 
       \           \ 
        ----------------------------------------------> grep World 

В одном из вопросов, связанных с ФП, существует (не принят, но правильный) ответ на F. Hauri, который я адаптировано здесь:

echo Hello World | 
((tee /dev/fd/5 | grep World >/dev/fd/4) \ 
      5>&1 | sed 's/World/Boy/' | grep Boy) 4>&1 

Это займет немного практики, чтобы читать bashisms как т он выше. Важной частью является то, что

(commands) 5>&1 

Создает подоболочку (()) и дает, что подоболочка FD номером 5, изначально скопированный из stdout (5>&1). Внутри подоболочки /dev/fd/5 относится к этому fd. В пределах подоболочки можно перенаправить stdout, но это произойдет после копирования stdout в fd5.

+0

Значит, он должен работать правильно? – SANDeveloper

+0

aaah. Подожди. Любое решение? – SANDeveloper

+0

@SANDeveloper: решение из ответа на вопрос, упомянутый вами в OP – rici

1

Вы можете использовать pee(1) - в Debian/Ubuntu он доступен в пакете moreutils.

Использование для примера, несколько более читабельным, чем волшебном перенаправлением

echo Hello World | pee 'grep World' 'sed "s/World/Boy/" | grep Boy' 
Смежные вопросы