7

我正在尝试创建一个 shell 脚本,我会将最新的 Atomic gotroot 规则下载到我的服务器,解压缩它们,将它们复制到正确的文件夹等,

我大部分时间都在阅读 shell 教程和论坛帖子,其中一些语法让我无法理解。我已经运行了所有这些命令,如果我手动运行它们,我知道它们会起作用。

我知道我需要开发一些错误检查,但我只是想让命令正确运行。目前的主要问题是 wget 命令的语法,我遇到了关于缺少分号、除以零、不受支持的方案的错误 - 我尝试了各种引用(单引号和双引号)和转义 - / " 字符各种组合。

谢谢你的帮助。原始 wget 命令是

wget --user="jim" --password="xxx-yyy-zzz" "http://updates.atomicorp.com/channels/rules/subscription/VERSION"

#!/bin/sh
update_modsec_rules(){

wget=/usr/bin/wget
tar=/bin/tar
apachectl=/usr/bin/apache2ctl


TXT="Script Run Finished"
WORKING_DIR="/var/asl/updates"
TARGET_DIR="/usr/local/apache/conf/modsec_rules/"
EXISTING_FILES="/var/asl/updates/modsec/*"
EXISTING_ARCH="/var/asl/updates/modsec-*"
WGET_OPTS='--user=jim --password=xxx-yyy-zzz'
URL_BASE="http://updates.atomicorp.com/channels/rules/subscription"


# change to working directory and cleanup any downloaded files and extracted rules in modsec/ directory
cd $WORKING_DIR
rm -f $EXISTING_ARCH
rm -f $EXISTING_FILES
rm -f VERSION*

# wget to download VERSION file
$wget ${WGET_OPTS} "${URL_BASE}/VERSION"

# get current MODSEC_VERSION from VERSION file and save as variable
source VERSION
TARGET_DATE=$MODSEC_VERSION
echo $TARGET_DATE

# wget to download current archive
$wget ${WGET_OPTS} "${URL_BASE}/modsec-${TARGET_DATE}.tar.gz"

# extract archive
echo "extracting files . . . "
tar zxvf $WORKING_DIR/modsec-${TARGET_DATE}.tar.gz

echo "copying files . . . "
cp -uv $EXISTING_FILES $TARGET_DIR

echo $TXT
}

update_modsec_rules $@ 2>&1 | tee -a /var/asl/modsec_update.log

RESTART_APACHE="/usr/local/cpanel/scripts/restartsrv httpd"
$RESTART_APACHE
4

2 回答 2

10

以下是编写 shell 脚本时使用的一些指南。

  1. 使用变量时始终引用它们。这有助于避免误解的可能性。(如果文件名包含空格怎么办?)
  2. 不要相信像rm. 改用for循环。(如果文件名以连字符开头怎么办?)
  3. 尽可能避免使用子shell。你带反引号的台词让我发痒。
  4. 如果您能帮上忙,请不要执行。尤其是不要指望exec 之后脚本的任何部分实际运行。

我应该指出,虽然您的 shell 可能是 bash,但您已指定/bin/sh执行此脚本,因此它不是 bash 脚本。

这是一个带有一些错误检查的重写。加盐调味。

#!/bin/sh

# Linux
wget=/usr/bin/wget
tar=/bin/tar
apachectl=/usr/sbin/apache2ctl

# FreeBSD
#wget=/usr/local/bin/wget
#tar=/usr/bin/tar
#apachectl=/usr/local/sbin/apachectl

TXT="GOT TO THE END, YEAH"
WORKING_DIR="/var/asl/updates"
TARGET_DIR="/usr/local/apache/conf/modsec_rules/"
EXISTING_FILES_DIR="/var/asl/updates/modsec/"
EXISTING_ARCH="/var/asl/updates/"

URL_BASE="http://updates.atomicorp.com/channels/rules/subscription"
WGET_OPTS='--user="jim" --password="xxx-yyy-zzz"'

if [ ! -x "$wget" ]; then
  echo "ERROR: No wget." >&2
  exit 1
elif [ ! -x "$apachectl" ]; then
  echo "ERROR: No apachectl." >&2
  exit 1
elif [ ! -x "$tar" ]; then
  echo "ERROR: Not in Kansas anymore, Toto." >&2
  exit 1
fi

# change to working directory and cleanup any downloaded files
# and extracted rules in modsec/ directory
if ! cd "$WORKING_DIR"; then
  echo "ERROR: can't access working directory ($WORKING_DIR)" >&2
  exit 1
fi

# Delete each file in a loop.
for file in "$EXISTING_FILES_DIR"/* "$EXISTING_ARCH_DIR"/modsec-*; do
  rm -f "$file"
done

# Move old VERSION out of the way.
mv VERSION VERSION-$$

# wget1 to download VERSION file (replaces WGET1)
if ! $wget $WGET_OPTS $URL_BASE}/VERSION; then
  echo "ERROR: can't get VERSION" >&2
  mv VERSION-$$ VERSION
  exit 1
fi

# get current MODSEC_VERSION from VERSION file and save as variable,
# but DON'T blindly trust and run scripts from an external source.
if grep -q '^MODSEC_VERSION=' VERSION; then
  TARGET_DATE="`sed -ne '/^MODSEC_VERSION=/{s/^[^=]*=//p;q;}' VERSION`"
  echo "Target date: $TARGET_DATE"
fi

# Download current archive (replaces WGET2)
if ! $wget ${WGET_OPTS} "${URL_BASE}/modsec-$TARGET_DATE.tar.gz"; then
  echo "ERROR: can't get archive" >&2
  mv VERSION-$$ VERSION         # Do this, don't do this, I don't know your needs.
  exit 1
fi

# extract archive
if [ ! -f "$WORKING_DIR/modsec-${TARGET_DATE}.tar.gz" ]; then
  echo "ERROR: I'm confused, where's my archive?" >&2
  mv VERSION-$$ VERSION         # Do this, don't do this, I don't know your needs.
  exit 1
fi
tar zxvf "$WORKING_DIR/modsec-${TARGET_DATE}.tar.gz"

for file in "$EXISTING_FILES_DIR"/*; do
  cp "$file" "$TARGET_DIR/"
done

# So far so good, so let's restart apache.
if $apachectl configtest; then
  if $apachectl restart; then
    # Success!
    rm -f VERSION-$$
    echo "$TXT"
  else
    echo "ERROR: PANIC! Apache didn't restart.  Notify the authorities!" >&2
    exit 3
  fi
else
  echo "ERROR: Apache configs are broken.  We're still running, but you'd better fix this ASAP." >&2
  exit 2
fi

请注意,虽然我已将其重写为更明智,但肯定还有很大的改进空间。

于 2013-11-14T03:59:41.003 回答
1

你有两个选择:

1-将其更改为

WGET1=' --user="jim" --password="xxx-yyy-zzz" "http://updates.atomicorp.com/channels/rules/subscription/VERSION"'

然后运行

wget $WGET1与 WGET2 相同

或者

2-用反引号封装 $WGET1 ``。例如:

`$WGET`

这适用于您从变量中执行的任何命令。

建议更改:

#!/bin/sh

TXT="GOT TO THE END, YEAH"
WORKING_DIR="/var/asl/updates"
TARGET_DIR="/usr/local/apache/conf/modsec_rules/"
EXISTING_FILES="/var/asl/updates/modsec/*"
EXISTING_ARCH="/var/asl/updates/modsec-*"
WGET1='wget --user="jim" --password="xxx-yyy-zzz" "http://updates.atomicorp.com/channels/rules/subscription/VERSION"'
WGET2='wget --user="jim" --password="xxx-yyy-zzz" "http://updates.atomicorp.com/channels/rules/subscription/modsec-$TARGET_DATE.tar.gz"'


## change to working directory and cleanup any downloaded files and extracted rules in modsec/ directory
cd $WORKING_DIR
rm -f $EXISTING_ARCH
rm -f $EXISTING_FILES

## wget1 to download VERSION file
`$WGET1`

## get current MODSEC_VERSION from VERSION file and save as variable
source VERSION
TARGET_DATE=`echo $MODSEC_VERSION`

## WGET2 command to download current archive
`$WGET2`
## extract archive
tar zxvf $WORKING_DIR/modsec-$TARGET_DATE.tar.gz

cp $EXISTING_FILES $TARGET_DIR

## restart server
exec '/usr/local/cpanel/scripts/restartsrv_httpd' $*;

专业提示:如果您需要字符串替换,使用 ${VAR} 可以更好地消除歧义,例如:

tar zxvf $WORKING_DIR/modsec-${TARGET_DATE}.tar.gz
于 2013-11-13T22:07:10.953 回答