【问题标题】:Using Functions inside here document在此处文档中使用函数
【发布时间】:2012-10-23 05:29:24
【问题描述】:

我有一个脚本,其中包含一些主体用来执行的函数。现在,我想在 3 台远程 unix 机器上运行这个脚本。哪种方法最简洁? 最重要的是,我不会为远程连接编写第二个脚本。一切都应该在这个脚本中。

我用 ssh 尝试过 heredoc,由于功能太大,它不起作用!

代码 -

#!/bin/bash

# Year Month Day Related functions
# FUNCTIONS
# Find no. of days in a year
yeardays()
{
# argument check
if [ X$1 = X ]
then
        read year
else
        year=$1
fi
# Check for leap years
if [ `expr $year % 400` = 0 ]
then
        echo 366
        exit
fi

if [ `expr $year % 100` = 0 ]
then
        echo 365
        exit
fi

if [ `expr $year % 4` = 0 ]
then
        echo 366
        exit
fi

echo 365
}

# Find no. of days in a Month
monthdays()
{
# argument check
if  [ X$1 = X ]
then
     read ymd   # year in yyyymmdd format
elif [ X$2 = X ]
then
      ymd=$1
else
      ymd=`expr \( $1 \* 10000 \) + \( $2 \* 100 \) + 1`
fi

year=`expr $ymd / 10000` ;
month=`expr \( $ymd % 10000 \) / 100` ;

case $month in
      1|3|5|7|8|10|12) echo 31 ; exit ;;
      4|6|9|11) echo 30 ; exit ;;
      *) ;;
esac

# except for month 2, which depends on whether the year is a leap year
# Use yeardays to get the number of days in the year and return a value
# accordingly.
daysInYear=`yeardays $year`

case $daysInYear in
   365) echo 28 ; exit ;;
   366) echo 29 ; exit ;;
esac
}

ymd2yd()    # convert from YYYYMMDD(gregorian) to YYYYDDD(julian)
{
# argument check
if [ X$1 = X ]
then
        read date
else
        date=$1
fi

year=`expr $date / 10000`
month=`expr \( $date % 10000 \) / 100`
days=`expr $date % 100`

count=1
while [ `expr $count \< $month` = 1 ]
do
        daysInMonth=`monthdays $year $count`
        days=`expr $days + $daysInMonth`
        count=`expr $count + 1`
done

julian=`expr \( $year \* 1000 \) + $days`
echo $julian
}

yd2ymd()    # convert from YYYYDDD(julian) to YYYYMMDD(gregorian)
{
# argument check
if [ X$1 = X ]
then
        read date
else
        date=$1
fi

year=`expr $date / 1000`
days=`expr $date % 1000`

month=1
while [ `expr $days \> 0` = 1 ]
do
        daysInMonth=`monthdays $year $month`
        days=`expr $days - $daysInMonth`
        month=`expr $month + 1`
done

days=`expr $days \+ $daysInMonth`
month=`expr $month \- 1`

gregorian=`expr \( $year \* 10000 \) + \( $month \* 100 \) + $days`
echo $gregorian
}

ydadd()     # Add/Subtract days to YYYYDDD format
{
# argument check
if [ X$2 = X ]
then
        difference=$1
        read yd     # Read the YYYYDDD format date
else
        yd=$1
        difference=$2
fi

days=`expr $yd % 1000`
year=`expr $yd / 1000`

days=`expr $days + $difference`
daysInYear=`yeardays $year`

while [ `expr $days \> $daysInYear` = 1 ]
do
        days=`expr $days - $daysInYear`
        year=`expr $year + 1`
        daysInYear=`yeardays $year`
done

while [ `expr $days \< 1` = 1 ]
do
        year=`expr $year - 1`
        daysInYear=`yeardays $year`
        days=`expr $days + $daysInYear`
done

yd=`expr \( $year \* 1000 \) + $days`       # Final date in YYYYDDD format
echo $yd
}

ymdadd()    # Add/Subtract days to YYYYMMDD format
{
if [ X$2 = X ]
then
        difference=$1
        read ymd    # Read YYYYMMDD format date
else
        ymd=$1
        difference=$2
fi

echo $ymd | ymd2yd | ydadd $difference | yd2ymd # Convert YYYYMMDD to YYYYDDD, perform date arithmetic, then revert to YYYYMMDD format
}

daysLeft()  # Calculate days between two dates in YYYYMMDD format
{
# argument check
if [ X$1 = X ]
then
        read ymd1   # First date in YYYYMMDD format
        read ymd2   # Second date in YYYYMMDD format
elif [ X$2 = X ]
then
        ymd1=$1
        read ymd2
else
        ymd1=$1
        ymd2=$2
fi

year1=`expr $ymd1 / 10000`
month1=`expr \( $ymd1 % 10000 \) / 100`
day1=`expr $ymd1 % 100`

year2=`expr $ymd2 / 10000`
month2=`expr \( $ymd2 % 10000 \) / 100`
day2=`expr $ymd2 % 100`

daysm1=`monthdays $year1 $month1`
days=`expr $daysm1 - $day1`
month1=`expr $month1 + 1`

while [ `expr $month1 \<= 12` = 1 ]
do
        daysm1=`monthdays $year1 $month1`
        days=`expr $days + $daysm1`
        month1=`expr $month1 + 1`
done

x=1
while [ `expr $x \< $month2` = 1 ]
do
        daysm2=`monthdays $year2 $x`
        days=`expr $days + $daysm2`
        x=`expr $x + 1`
done

days=`expr $days + $day2`
echo $days
}

# MAIN BODY
# Connect to different Servers
declare -a SERVER=('server1' 'server2' 'server3')
remoteUser=abc
serverNumbers=${#SERVER[@]}
count=0
while [ `expr $count \< $serverNumbers` = 1 ]
do
    # Connect to  server
    ssh -T -q $remoteUser@${SERVER[count]} <<-"END_TEXT"
    VALUE=`cat /home/cognos/cognos/c8/configuration/cogstartup.xml | grep -i xsd:long | head -1 | cut -d">" -f2 | sed 's/[:/<|crn:value]*//g'`
    VALUE_BACKUP=$VALUE
    let 'VALUE -= 30'       
    let 'VALUE *= 86400'
    RESULT1=`perl -e '@stats = stat("/home/cognos/cognos/c8/configuration/signkeypair"); print ((time - $stats[9]) < "$VALUE");'`
    RESULT2=`perl -e '@stats = stat("/home/cognos/cognos/c8/configuration/encryptkeypair"); print ((time - $stats[9]) < "$VALUE");'`
    RESULT3=`perl -e '@stats = stat("/home/cognos/cognos/c8/configuration/caSerial"); print ((time - $stats[9]) < "$VALUE");'`
    while [ "$RESULT1" -o "$RESULT2" -o "$RESULT3" ]
    do
            echo "Sending mail."
            # Calculate days left
            CURRENT_DATE=`date +"%Y-%m-%d" | sed 's/-//g'`
            CREATION_DATE=`ls -logE /home/cognos/cognos/c8/configuration/ | grep -i signkeypair | awk '{print $4}' | sed 's/-//g'`
            EXPIRY_DATE=`ymdadd $CREATION_DATE $VALUE_BACKUP`
            DAYS_LEFT=`daysLeft $CURRENT_DATE $EXPIRY_DATE`
            # Identify environment from hostname - DEV/UAT/PRD
            LOCALHOST=`hostname`
            ENVIRONMENT_TYPE=`echo $LOCALHOST | perl -ne '~m/.*([a-zA-Z]{3})[0-9]*$/; print $1;'|tr '[a-z]' '[A-Z]'`
            # Identify process - FormPF/GoReporting
            if (echo $LOCALHOST | grep -i cfp >/dev/null) then
                   PROCESS="FormPF"
            else
                   PROCESS="GoReporting"
            fi
            # Add details to mail body
            echo "The key was created on `ls -log /home/cognos/cognos/c8/configuration/ | grep -i signkeypair | awk '{print $4,$5,$6}'`, and was set to expire after $VALUE_BACKUP days." > mail.txt
            echo "Key expires in $DAYS_LEFT days !!" >> mail.txt
            echo " " >> mail.txt
            echo "The server is-" >> mail.txt
            hostname >> mail.txt
            echo " " >> mail.txt
            echo "Status of folders/files-" >> mail.txt
            echo " " >> mail.txt
            ls -log /home/cognos/cognos/c8/configuration/ | grep -i signkeypair | awk '{print $4,$5,$6,$7}' >> mail.txt
            ls -log /home/cognos/cognos/c8/configuration/ | grep -i encryptkeypair | awk '{print $4,$5,$6,$7}' >> mail.txt
            ls -log /home/cognos/cognos/c8/configuration/ | grep -i caSerial | awk '{print $4,$5,$6,$7}' >> mail.txt
        echo " " >> mail.txt
        echo "To reactive key, please restart the server at weekend with below options:" >> mail.txt
        echo " " >> mail.txt
        echo "/home/cognos/etc/restartAllServers.sh -cdsk" >> mail.txt
            # Send warning mail !!
            SUBJECT="!! ($ENVIRONMENT_TYPE) $PROCESS ($LOCALHOST) Cognos CSK(Common Symmetric Key) Expiry !!"
            EMAIL="xyz@abc.com"
            cat mail.txt | mailx -s "$SUBJECT" "$EMAIL"
        rm mail.txt
            break
    done
    logout
    END_TEXT
    count=`expr $count + 1`
done
exit 0

【问题讨论】:

  • 不错的脚本,但是您希望您如何远程执行脚本(通过 ssh)来找到您定义的功能。您可以将它们安装在远程机器上,也可以像完成脚本主体一样“通过网络”发送它们。请注意,ssh 可以传递内联命令的内容有明确的大小限制,并且您可能会在错误的时间遇到​​变量扩展问题,这需要特殊引用和转义字符等。祝你好运。
  • @shellter 我试过“通过网络”发送整个脚本,但徒劳无功。是否可以在此脚本中使用 scp 而不会陷入无限循环?
  • if [ $( expr ... ) = 0 ]; then ... 让我的眼睛受伤了。相反,请使用:if expr ... &gt; /dev/null; then ...
  • 请注意,&lt;&lt;- 只去除前导 制表符 字符,而不是任意空格(请参阅the manual)。
  • @WilliamPursell,glennjackman 谢谢大家

标签: bash shell unix


【解决方案1】:

在 heredoc 中移动函数。它可能需要对代码结构进行一些更改,但它会起作用。

ssh app01.datacentre.private <<EOD
hostdatefunc () {
echo \$(hostname) \$(date)
}
hostdatefunc
EOD

您将获得远程服务器上的主机名和日期,而不是您的。作品。愚蠢的例子,但概念证明。

【讨论】:

  • heredoc 可以包含函数吗?我想我必须把函数放在变量中,然后放在heredoc中。你说的是什么变化?
  • @kaustavdatta 我的示例有效,因此函数有效。当然,您需要知道远程主机上正在使用哪种 shell。至于更改 - 好吧,我没有详细阅读您的脚本 - 如果这些函数在 heredoc 之外以及在其中使用,那么您必须将它们复制到 heredoc 中,而不是移动它们。
  • 你必须引用EOD,否则你会得到本地主机名和日期。
  • @kaustavdatta 中的变量在heredoc 被读取之前被扩展;其他所有内容都只是通过 STDIN 传递给正在调用的程序。因此,这些函数作为文本行传递给 ssh,后者在与 bourne 兼容的 shell(您希望)中运行它们,因此它们可以工作。
  • 我必须使用 ssh -T 否则我会收到此错误 - 不会分配伪终端,因为 stdin 不是终端。这是为什么呢??
猜你喜欢
  • 2011-03-05
  • 1970-01-01
  • 2016-05-01
  • 2013-04-04
  • 2021-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多