Следующий пример представляет собой своего рода классический способ использования каналов. Справа от канала у нас есть «простая» утилита, которая считывает данные из стандартного ввода (канала) и выводит на стандартный вывод в обратном порядке:
{ cat <</EOF
Hello
World
/EOF
} | rev
Очевидно, что результат таков:
olleH
dlroW
Теперь я хочу передать эти данные через канал в команда/утилита, которая является частью оболочки here-doc:
{ cat <</EOF
Hello
World
/EOF
} | ksh -x <</EOF
rev
/EOF
Это не работает, нет сообщения об ошибке, ничего, переданные данные теряются, так как ksh перенаправляет stdin на here-doc.
Пробовал какое-то перенаправление:
set -x
{ cat <</EOF
Hello
World
/EOF
} | { exec 4<&0; ksh -x <</EOF; exec 0<&4 4<&-; }
rev <&4
/EOF
Но и это не работает, показывает ошибку по команде rev, очевидно перенаправление stdin на fd4 не передается подпроцессам ksh:
+ exec
+ 4<& 0
+ ksh -x
+ cat
+ 0<< \/EOF
rev <&4
/EOF
+ 0<< \/EOF
Hello
World
/EOF
+ rev
+ ksh[1]: 4: cannot open [Ungültiger Dateideskriptor]
+ exec
+ 0<& 4 4<& -
Я застрял здесь.
Мое реальное приложение намного сложнее: в левой части канала я выполняю ssh для исходного сервера, опционально sudo для другого пользователя на этом сервере и запускаю tar для передачи некоторых файлов данных. С правой стороны трубы мне нужно будет подключиться по ssh к целевому серверу, при желании sudo к другому пользователю и, наконец, запустить tar для получения данных из трубы.
Кстати: все работает нормально, если я НЕ использую here-doc в правой части канала:
{ cat <</EOF
Hello
World
/EOF
} | ksh -xc "rev"
Даже с ssh плюс sudo плюс tar это работает нормально. По какой-то причине я бы предпочел, чтобы документация по оболочке находилась справа. Как видите, ksh — моя любимая оболочка в этом приложении.
В соответствии с запросом: мое исходное утверждение похоже на
ssh $SSHOPT $INST_FILE_USER@$INST_FILE_HOST "cd $IDIR && { tar -cvf - $IFIL && echo RCSRC0 >&2 || echo RCSRC1 >&2; }" 2>$TMPFILE.err.src | ssh $SSHOPT $TRG_USER@$TRG_HOST "cd $TDIR && { tar -xmvf - && echo RCTRG0 || echo RCTRG1; }" 1>$TMPFILE.out.trg 2>&1
Пока все работает нормально. Как видите, реализован минимум проверки ошибок, что позволяет распознавать успех tar. Теперь я должен добавить функциональность sudo, это означает, что между оболочкой из ssh и командой cd я должен добавить некоторый код для переключения пользователя. Это действительно судо, которое будет использоваться? Это может быть команда pbrun, так как клиенты могут предпочесть pbrun. С этими различными сценариями можно справиться гораздо гибче, если вместо одного оператора-монстра будут использоваться здесь-документы.
Обновление от 21 мая: Я пытался следовать рекомендациям, данным до сих пор, но я все еще застрял. Давайте посмотрим на приведенный ниже ответ, который у меня работает нормально:
echo yup | ksh -c 'exec 4<&0; ksh -c "rev <&5" 5<&4'
puy
Если я начну использовать ssh или использовать ssh в сочетании с sudo, мой пример с перенаправлением больше не работает:
echo yup | ssh admin@trg14 ksh -c 'exec 4<&0; ksh -c "rev <&5" 5<&4'
bash: 4: Bad file descriptor
echo yup | ssh admin@trg14 sudo -n -u trg4 ksh -c 'exec 4<&0; ksh -c "rev <&5" 5<&4'
bash: 4: Bad file descriptor
Я пробовал 2 сценария с Комбинация ssh и sudo: первая использует here-doc в качестве входных данных для ksh:
Сценарий 1:
echo yup | ssh admin@trg14 sudo -n -u trg4 -- ksh<</EOF
whoami && whoami && rev && whoami
/EOF
trg4
trg4
trg4
Это работает до сих пор. Примечание: все 4 команды запускаются от имени пользователя trg4, rev не получает никаких входных данных через канал, как ожидалось, из-за здесь-документа.
Поэтому я попытался реализовать решение, предложенное ниже: здесь-doc будет вводиться как параметр ksh:
Сценарий 2:
echo yup | ssh admin@trg14 sudo -n -u trg4 -- ksh -c "$(cat<</EOF
whoami && whoami && rev && whoami
/EOF
)"
trg4
admin
puy
admin
Вывод из rev соответствует ожидаемому, но: whoami показывает нам, что в этой версии/реализации только первая команда first запускается от имени пользователя sudo, остальные команды будут выполняться от имени пользователя ssh! В случае rev нет проблем, но если вам нужно получить доступ к файлам базы данных или записать их, у вас не будет проблем с разрешениями.
Вывод из этих двух примеров: сценарий 1 может быть правильным путем для запуска всех команд под правильным пользователем sudo, но для использования конвейера потребуется решение перенаправления стандартного ввода.
Любая помощь приветствуется!
[вы должны задать другой вопрос о другой проблеме, вместо того, чтобы копаться в этом]
Когда вы запускаете ssh
с [command]
аргументами, как в ssh user@host foo bar baz
, происходит следующее: его аргументы будут объединены пробелами в один аргумент, который будет передан через -c
] переключиться на оболочку входа пользователя на удаленной машине (, если эта оболочка /bin/sh
, /bin/sh -c 'foo bar baz'
будет запущена ).
Теперь, что происходит в вашем примере:
echo yup | ssh admin@trg14 ksh -c 'exec 4<&0; ksh -c "rev <&5" 5<&4'
заключается в том, что аргументы ssh будут объединены в строку:
ksh -c exec 4<&0; ksh -c "rev <&5" 5<&4
и сначала запустится оболочка на удаленной машине
ksh -c exec 4<&0
, а затем
ksh -c "rev <&5" 5<&4
как две отдельные команды, и конечно fd 4 во второй ни на что не указывает, потому что он был только перенаправлен в первой команде.