LINUX.ORG.RU
ФорумAdmin

выполнение bash-скрипта на удалённом сервере по ssh

 


0

4

Хочу в bash-скрипте реализовать выполнение bash-скрипта на удалённом сервере по ssh, при этом текст удалённого скрипта должен быть встроен в текст вызывающего скрипта на локальном компьютере.
Сделал так: скрипт выводит данные о потреблении памяти процессом httpd на удалённом сервере:

#!/bin/bash

ssh -i /home/iskatel/id_rsa iskatel@172.17.17.1 <<'ENDSSH'
   cat /proc/$(cat /run/httpd/httpd.pid)/status | grep VmSize | awk '{print $1 $2*1024}'
   cat /proc/$(cat /run/httpd/httpd.pid)/status | grep VmRSS | awk '{print $1 $2*1024}'
ENDSSH

Подскажите, что неправильно в этом скрипте. Так то скрипт данные из /proc на удалённом сервере выводит, но он при этом на удалённом сервере bash запускается как login shell.

★★★★★

Тебе так и так нужно какой-нибудь интерпретатор указать, чтобы он переварил скормленный скрипт. Можешь что-то типа «/bin/sh -» прописать.

Radjah ★★★★★ ()

Так-с, переделал. grep убрал

#!/bin/bash

SCRIPT0=$(cat << 'EOF'
   cat /proc/$(cat /run/httpd/httpd.pid)/status | awk '/VmSize/{print $1 $2*1024}'
   cat /proc/$(cat /run/httpd/httpd.pid)/status | awk '/VmRSS/{print $1 $2*1024}'
EOF
)

echo "$SCRIPT0" | ssh -i /home/iskatel/id_rsa iskatel@172.17.17.1
sunny1983 ★★★★★ ()
Последнее исправление: sunny1983 (всего исправлений: 1)

cat file.sh | ssh user@host 'cat | bash'

Вместо cat file.sh можно, например, sed'ом / tail'ом и так далее «срезать» часть скрипта, где указано подключение.

rain@walkbook:/tmp$ cat file.sh 
#!/bin/bash
tail -n +4 $0 | ssh miner10 'cat | bash'
exit

hostname

/home/rain/bin/sysinfo.sh
rain@walkbook:/tmp$ ./file.sh 
miner10
* 2 x model name        : Intel(R) Pentium(R) CPU G4400 @ 3.30GHz
* RAM: 3.89 GB
* Disk /dev/sda: 55.9 GiB
* GPU (8)
 * GeForce GTX 1070 Ti          8119 MiB (ID: GPU-61f553d9-1080-3856-8fc8-00a2476c0381)
 * GeForce GTX 1070 Ti          8119 MiB (ID: GPU-0cc8f6c1-c21d-a309-a434-733256f55ed3)
 * GeForce GTX 1070 Ti          8119 MiB (ID: GPU-3412ed55-faea-8cea-0bd3-066cc6dd9db6)
 * GeForce GTX 1070 Ti          8119 MiB (ID: GPU-7ed2c525-e616-b436-b146-64ba7d3442df)
 * GeForce GTX 1070 Ti          8119 MiB (ID: GPU-78f3cd1c-5332-82bc-ed14-fea6b39269b2)
 * GeForce GTX 1070 Ti          8119 MiB (ID: GPU-bd18879a-0e38-f9eb-ecc7-929360c9b43b)
 * GeForce GTX 1070 Ti          8119 MiB (ID: GPU-15a148e6-d4c2-9e20-7735-03e0d6d88e4a)
 * GeForce GTX 1070 Ti          8119 MiB (ID: GPU-6c8a32dc-8326-d955-9b06-1cfc11e1bad0)

YAR ★★★★★ ()
Последнее исправление: YAR (всего исправлений: 1)
Ответ на: комментарий от Bers666

Сейчас задача стоит не мониторинг разворачивать, а впендюрить скрипт в уже имеющийся колхозный мониторинг, а заодно и повысить свой навык скриптописательства.

sunny1983 ★★★★★ ()

Расширяю задачу. Сделать скрипт универсальным, способным мониторить не только httpd на конкретном сервере, но и любой процесс на любом сервере, зная IP и PID-файл.

#!/bin/bash

SCRIPT0=$(cat << 'EOF'
   cat /proc/$(cat "$2")/status | awk -v OFS='' '/VmSize/{print $1,$2*1024," "}'
   cat /proc/$(cat "$2")/status | awk  -v OFS='' '/VmRSS/{print $1,$2*1024}'
EOF
)

echo "$SCRIPT0" | /usr/bin/ssh -i /home/iskatel/id_rsa cacti@"$1" /bin/bash | tr -d '\n'

Не работает. $2 во внутренний скрипт не передаётся.

sunny1983 ★★★★★ ()
Последнее исправление: sunny1983 (всего исправлений: 1)

Это выглядит просто:

sshpass -p $passw ssh -o "ConnectTimeout=3" -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking
        aplay -q $sound
Это конечно прмер. И переменные из другого скрипта.

Bootmen ★☆☆ ()
Ответ на: комментарий от sunny1983

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

тут есть классные спецы кто может объяснить

@vodz

@mky

nerve ★★ ()
Ответ на: комментарий от sunny1983

Не работает. $2 во внутренний скрипт не передаётся.

При heredoc в кавычках ('EOF'), $ — не спец символ.

А вообще вам же дали правильное решение из первого комента:

HTTPD_PID=/var/run/httpd/httpd.pid

SCRIPT0='
/VmSize/ { VmSize=$2*1024 }
/VmRSS/  { VmRSS=$2*1024 }
END { print "VmSize=" VmSize " VmRSS=" VmRSS }
'

ssh $1 /usr/bin/env awk "'$SCRIPT0'" "/proc/\$(cat $HTTPD_PID)/status"

vodz ★★★★★ ()
Ответ на: комментарий от vodz

Наверное я не воспользовался этим решением потому, что его не понял, awk я тоже осваиваю сейчас параллельно с bash, но понимать многострочные awk-скрипты для меня сейчас - слишком сложно, поэтому и выбрал решение из внешнего скрипта запустить внутренний скрипт по ssh, а потом отформатировать его вывод в awk, и соответственно нужно, чтобы параметры раскрывались во внешнем скрипте.

sunny1983 ★★★★★ ()
Ответ на: комментарий от sunny1983

соответственно нужно, чтобы параметры раскрывались во внешнем скрипте.

Локальные параметры должны раскрываться локально и никакое «соответственно» быть не может.

vodz ★★★★★ ()
Ответ на: комментарий от anonymous

кому должны?

Логике.

\$2

Если у вас скрипт уже лежит в виде файла на удаленной стороне, то слеш тут не нужен, если скрипт со стандартного ввода, то аргументов не передать.

vodz ★★★★★ ()
Ответ на: комментарий от anonymous

хорошо, разверну

$var=$2

Вы имели в виду var=$2 ? Ну зачем-то ввели дополнительную переменную var, её ояпть таки локально разрезольвили из $2, но на удаленную сторону передаёте в виде имени переменной, где на удаленной стороне там может быть своё значение или вообще никакого.

Перед тем как комментить рекомендуется всё же подумать и проверить.

vodz ★★★★★ ()
Ответ на: комментарий от anonymous

клован, это и есть упрощённый рабочий пример

А то и видно, что стыдно зарегиться, чтобы видели какого идиота и читать не стоит.

wwns=(...)
ssh ${host} <<EOF
  for wwn in ${wwns[@]}; do # тут будет локальной резольвинг
    echo \${wwn} # тут передастся имя удаленной стороне, что будет ТАМ - никто не знает
vodz ★★★★★ ()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от vodz

что будет ТАМ

там будет ровно то, что ты туда передашь

никто не знает

ало, регистрант ты наш болезный, так не пиши так, чтобы никто не знал, что там на другой стороне

ах да, тыж преподаватель, о чём это я

anonymous ()
Ответ на: комментарий от anonymous

там будет ровно то, что ты туда передашь

Нет. Там будет имя переменной, которую вы локально прорезольвили из списка в цикле, ибо это и есть for var in w[0]...w[n], В оригинальной задаче не стояло передать массив с неопределенным количеством аргументов, а передать конкретный набор переменных. ЧТД.

vodz ★★★★★ ()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от vodz

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

ты, неандерталец, не можешь даже в примеры? муахахахаха

короче, тс проверит и отпишется, а пока, ты можешь себе заочно по губам провести

anonymous ()
Ответ на: комментарий от anonymous

ты, неандерталец, не можешь даже в примеры? муахахахаха

О, да вы батенька ещ1 тупее, чем я вначале думал.

Написать:

sssh host << EOF
var=value
echo \$var
EOF
конечно можно, оно даже будет работать, но с точки зрения логики - совершенная бессмыслица.

короче, тс проверит и отпишется,

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

vodz ★★★★★ ()
Ответ на: комментарий от vodz

тс проверит и отпишется

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

Локальные параметры должны раскрываться локально

В принципе да, глобальный параметр $2 должен раскрываться во внешнем скрипте, передаваться во внутренний и там раскрываться ещё раз, приведённый пример - это просто пример, на самом деле во внутреннем скрипте может быть не 2 строки, а 200, и желательно и в этом случае, чтобы код оставался читаемым. Добавил ключ -s в вызов внутреннего bash и сделал так:

#!/bin/bash

SCRIPT0=$(cat << 'EOF'
   cat /proc/$(cat "$1")/status | awk -v OFS='' '/VmSize/{print $1,$2*1024," "}'
   cat /proc/$(cat "$1")/status | awk  -v OFS='' '/VmRSS/{print $1,$2*1024}'
EOF
)

echo "$SCRIPT0" | /usr/bin/ssh -i /home/iskatel/id_rsa iskatel@"$1" /bin/bash -s "$2" | tr -d '\n'
И кстати работает

sunny1983 ★★★★★ ()
Ответ на: комментарий от sunny1983

В принципе да, глобальный параметр $2 должен раскрываться во внешнем скрипте, передаваться во внутренний и там раскрываться ещё раз, приведённый пример - это просто пример, на самом деле во внутреннем скрипте может быть не 2 строки, а 200, и желательно и в этом случае, чтобы код оставался читаемым.

Исходя из этого принципа пишут псевдонимы к позиционным параметрам $N в виде самодокументируемых имен типа $HTTPD_PID. Тут собственно и все речь и ведут, как красивее и правильнее составить скрипт, ваша идея со всех сторон не правильна принципиально. Ладно, вот вам башизный фокус:

HTTPD_PID="/run/httpd/httpd.pid"

SCRIPT0="HTTPD_PID='$HTTPD_PID'; "

SCRIPT0+=$(cat << 'EOF'
cat /proc/$(cat "$HTTPD_PID")/status | ... и так далее

vodz ★★★★★ ()
Последнее исправление: vodz (всего исправлений: 1)