脚本参考
推送 ssh 公钥
基于 sshpass
sshpass 是一个 Linux 命令行工具,用于在非交互式的 SSH 会话中提供密码,以避免在脚本或自动化过程中手动输入密码。
通常,当你通过 SSH 连接到远程计算机时,需要手动输入密码来验证你的身份。但在脚本或自动化过程中,这不是很方便,因为你需要手动输入密码,这会打破自动化的流程。sshpass 可以避免这个问题,它可以自动提供 SSH 连接所需的密码,从而使得在脚本或自动化过程中连接到远程计算机更加方便。
需要注意的是,使用 sshpass 可能会存在安全风险,因为密码明文保存在脚本中。如果你需要在脚本中使用 sshpass,请确保只有有权访问脚本的人可以访问这些密码。
方案一
- 通过变量传入IP
#!/bin/bash
TARGET_IP_LIST="
10.0.0.18
10.0.0.28
"
PUBLIC_KEY_PATH="/root/.ssh/id_rsa"
#dpkg -L sshpass &> /dev/null || apt -y install sshpass
rpm -q sshpass &> /dev/null || yum -y install sshpass
#[ -f /root/.ssh/id_rsa ] || ssh-keygen -f /root/.ssh/id_rsa -P ''
if [ ! -f ${PUBLIC_KEY_PATH} ]; then
ssh-keygen -f ${PUBLIC_KEY_PATH} -P ''
fi
export SSHPASS=123
for IP in ${TARGET_IP_LIST}; do
{
sshpass -e ssh-copy-id -o StrictHostKeyChecking=no ${IP}
}&
done
wait该shell脚本中for循环中的 {}& 和外面的 wait 分别是什么意思
在这个脚本中,{}和&分别是两个不同的符号,具有不同的含义。
{}是一种将多个命令组合成一个单元的方法。在这个脚本中,{}将sshpass命令与ssh-copy-id命令组合在一起,这样这两个命令就可以在一个子shell中并行执行。
&是一种在后台执行命令的方法。在这个脚本中,&用于将多个{}中的子shell放入后台执行。这样做可以加快脚本的执行速度。
wait命令则是一种等待后台任务完成的方法。在这个脚本中,wait命令将会等待所有的子shell完成,然后再继续执行脚本中的其它命令。
为什么要加 wait?不加 wait 不行吗
如果不加wait命令,那么脚本将会立即继续执行,不会等待子shell完成。这样可能会导致一些问题,例如:
- 如果脚本后面的命令需要使用子shell中创建的文件或者数据,那么这些命令可能会因为在子shell还未完成的情况下执行而失败。
- 如果某个子shell执行失败,而脚本没有等待所有子shell完成就继续执行后续命令,那么可能会导致后续命令执行失败或者出现意料之外的错误。
因此,加上wait命令可以确保所有子shell都已经执行完毕后再继续执行后续命令,避免出现上述问题。
方案二
- 将IP列表赋值到文件中传入IP
- 您可以通过将IP列表保存在单独的文件中,然后在shell脚本中读取该文件来实现从外部文件传入IP列表。以下是示例脚本:
#!/bin/bash
PUBLIC_KEY_PATH="/root/.ssh/id_rsa"
IP_LIST_FILE="$1"
## 检查是否提供IP列表文件作为参数
if [ -z "$IP_LIST_FILE" ]; then
echo "IP列表文件未作为参数提供!"
exit 1
fi
## 检查IP列表文件是否存在
if [ ! -f "$IP_LIST_FILE" ]; then
echo "IP列表文件不存在!"
exit 1
fi
## 检查是否安装了sshpass
if ! command -v sshpass &> /dev/null; then
echo "sshpass未安装!请先安装。"
exit 1
fi
## 检查公钥是否存在,如果不存在,则生成一个
if [ ! -f ${PUBLIC_KEY_PATH} ]; then
ssh-keygen -f ${PUBLIC_KEY_PATH} -P ''
fi
export SSHPASS=123
while read -r IP; do
{
sshpass -e ssh-copy-id -o StrictHostKeyChecking=no "$IP"
}&
done < "$IP_LIST_FILE"
wait## cat host_list.conf
10.0.0.18
10.0.0.28
## bash 1.sh host_list.conf
...
[root@8 ~]# ssh 10.0.0.18
Last login: Fri Mar 31 11:34:46 2023 from 10.0.0.201
[root@18 ~]# logout
Connection to 10.0.0.18 closed.
[root@8 ~]# ssh 10.0.0.28
Last login: Fri Mar 31 11:34:49 2023 from 10.0.0.201
[root@28 ~]# 基于 expect
expect 是一个 Linux 命令行工具,可以用来自动化和自动化交互式命令行应用程序。
它的主要作用是在非交互式的脚本中模拟人工交互,使得脚本可以与交互式应用程序进行交互,例如 Telnet、FTP、SSH 和 MySQL 等。
通过 expect,你可以编写脚本来模拟交互式命令行的操作,例如输入用户名和密码、选择菜单选项、输入命令等。在脚本中使用 expect,可以自动化这些交互式的操作,避免手动输入。
需要注意的是,使用 expect 可能会存在安全风险,因为密码明文保存在脚本中。如果你需要在脚本中使用 expect,请确保只有有权访问脚本的人可以访问这些密码。
#!/bin/bash
## #********************************************************************
#Author: xiangzheng
#QQ: 767483070
#Date: 2022-04-20
#FileName: push_ssh_key_expect.sh
#URL: https://www.xiangzheng.vip
#Email: rootroot25@163.com
#Description: 批量推送公钥到远程主机以实现ssh免密登录
#Copyright (C): 2022 All rights reserved
#********************************************************************
## 此脚本在每台主机执行即可实现相互的ssh免密登录
## 远程主机和本机的IP
IP_LIST="
10.0.0.8
10.0.0.100
10.0.0.101
10.0.0.102
"
#远程主机和本机的密码
PASS="123"
#dpkg -L expect &> /dev/null || apt -y install expect
rpm -q expect &> /dev/null || yum -y install expect
#生成公钥私钥对,默认不为私钥创建密码,需要创建密码的话在-P后面的""中指定密码
#ssh-keygen -f /root/.ssh/id_rsa -t rsa -P ""
#判断公钥是否存在
[ -f ~/.ssh/id_rsa.pub ] || { echo '公钥不存在 请存放在 ~/.ssh/id_rsa.pub下 退出' ; exit 3; }
#使用 for 以IP变量的方式将公钥推送到远程主机组
for IP in ${IP_LIST};do
expect <<EOF
set timeout 20
spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@${IP}
expect {
"*yes/no*" { send "yes\n";exp_continue }
"*password*" { send "${PASS}\n" }
}
expect eof
EOF
echo ${IP} push succeed
done
#使用 while read 以配置文件的方式将公钥推送到远程主机组
#while read IP ;do
#expect <<EOF
#set timeout 20
#spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@${IP}
#expect {
## "*yes/no*" { send "yes\n";exp_continue }
## "*password*" { send "${PASS}\n" }
#}
#expect eof
#EOF
#echo ${IP} push succeed
#done < hosts.txtMySQL 数据库备份
基于 mysqldump
全库备份
#!/bin/bash
TIME=`date +%F_%H-%M-%S`
DIR=/backup/all_bak_${TIME}
#PASS=passwd
[ -d "$DIR" ] || mkdir $DIR && cd $DIR
#databases
mysqldump -uroot -F --single-transaction --source-data=2 -q -A | gzip > ${DIR}/all_backup_${TIME}.sql.gz
#log_bin
mkdir log_bin_backup
cp -a /data/mysql_bin log_bin_backup/
#config
mkdir config
cp -a /etc/my.cnf.d/mariadb-server.cnf config/#!/bin/bash
## 定义 MySQL 登录信息
MYSQL_USER="root"
MYSQL_PASSWORD="password"
## 定义备份文件保存目录
BACKUP_DIR="/var/backups/mysql"
## 定义备份文件名,使用日期作为后缀
BACKUP_FILE="$BACKUP_DIR/mysql-$(date +%Y-%m-%d).sql"
## 确保备份目录存在
mkdir -p $BACKUP_DIR
## 使用 mysqldump 备份所有数据库到指定的文件中
mysqldump -u $MYSQL_USER -p$MYSQL_PASSWORD --all-databases > $BACKUP_FILE
## 删除旧的备份文件,只保留最近7天的备份
find $BACKUP_DIR -name "mysql-*.sql" -type f -mtime +7 -delete分库备份
#!/bin/bash
TIME=`date +%F_%H-%M-%S`
DIR=/backup/branch_${TIME}
#PASS=passwd
[ -d "$DIR" ] || mkdir $DIR && cd $DIR
for DB in `mysql -uroot -e 'show databases' | grep -Ev "^Database|.*schema$"`;
do
mysqldump -F --single-transaction --source-data=2 -q -B $DB | gzip > branch_${DB}_${TIME}.sql.gz
done指定库备份
#!/bin/bash
TIME=`date +%F_%H-%M-%S`
DIR=/backup
DB=hellodb #指定数据库
PASS=12345
mysqldump -uroot -p "$PASS" -F –E –R --triggers --single-transaction --source-data=2 -q -B $DB | gzip > ${DIR}/${DB}_${TIME}.sql.gz创建证书
基于 openssl
#!/bin/bash
. /etc/init.d/functions
declare -A CERT_INFO
CERT_INFO=([subject0]="/O=heaven/CN=ca.god.com" \
[keyfile0]="cakey.pem" \
[crtfile0]="cacert.pem" \
[key0]=2048 \
[expire0]=3650 \
[serial0]=0 \
[subject1]="/C=CN/ST=liaoning/L=shenyang/O=Central.Hospital/CN=master.xiangzheng.org" \
[keyfile1]="master.key" \
[crtfile1]="master.crt" \
[key1]=2048 \
[expire1]=365
[serial1]=1 \
[csrfile1]="master.csr" \
[subject2]="/C=CN/ST=liaoning/L=shenyang/O=Central.Hospital/CN=slave.xiangzheng.org" \
[keyfile2]="slave.key" \
[crtfile2]="slave.crt" \
[key2]=2048 \
[expire2]=365 \
[serial2]=2 \
[csrfile2]="slave.csr" )
COLOR="echo -e \\E[1;32m"
END="\\E[0m"
DIR=/data
cd $DIR
for i in {0..2};do
if [ $i -eq 0 ] ;then
openssl req -x509 -newkey rsa:${CERT_INFO[key${i}]} -subj ${CERT_INFO[subject${i}]} \
-set_serial ${CERT_INFO[serial${i}]} -keyout ${CERT_INFO[keyfile${i}]} -nodes \
-days ${CERT_INFO[expire${i}]} -out ${CERT_INFO[crtfile${i}]} &>/dev/null
else
openssl req -newkey rsa:${CERT_INFO[key${i}]} -nodes -subj ${CERT_INFO[subject${i}]} \
-keyout ${CERT_INFO[keyfile${i}]} -out ${CERT_INFO[csrfile${i}]} &>/dev/null
openssl x509 -req -in ${CERT_INFO[csrfile${i}]} -CA ${CERT_INFO[crtfile0]} \
-CAkey ${CERT_INFO[keyfile0]} -set_serial ${CERT_INFO[serial${i}]} \
-days ${CERT_INFO[expire${i}]} -out ${CERT_INFO[crtfile${i}]} &>/dev/null
fi
$COLOR"**************************************生成证书信息**************************************"$END
openssl x509 -in ${CERT_INFO[crtfile${i}]} -noout -subject -dates -serial
echo
done
chmod 600 *.key
action "证书生成完成"
$COLOR"**************************************生成证书文件如下**************************************"$END
echo "证书存放目录: "$DIR
echo "证书文件列表: "`ls $DIR`部署应用
安装 JDK
#!/bin/bash
## #********************************************************************
#Author: xiangzheng
#QQ: 767483070
#Date: 2021-07-07
#FileName: install_jdk.sh
#URL: llinux.cn
#Description: The test script
#Copyright (C): 2021 All rights reserved
#********************************************************************
JDK_FILE="/usr/local/src/jdk-8u333-linux-x64.tar.gz"
JDK_TARGET="/usr/local"
JDK_UN_NAME="jdk1.8.0_333" # jdk 版本
if $(java -version &> /dev/null); then
echo "JDK 已经安装 退出"
exit
elif [ ! -f "$JDK_FILE" ]; then
echo "$JDK_FILE 文件不存在 退出"
exit
fi
tar xvf $JDK_FILE -C $JDK_TARGET
ln -s $JDK_TARGET/$JDK_UN_NAME $JDK_TARGET/jdk
cat > /etc/profile.d/jdk.sh <<EOF
export JAVA_HOME=$JDK_TARGET/jdk
export JRE_HOME=\$JAVA_HOME/jre
export CLASSPATH=\$JAVA_HOME/lib/:\$JRE_HOME/lib/
export PATH=\$PATH:\$JAVA_HOME/bin
EOF
. /etc/profile.d/jdk.sh
java -version &> /dev/null && echo "${JDK_FILE%%.*} 安装完成" || { echo "${JDK_FILE%%.*} 安装失败" ; exit ; }安装 Harbor
#!/bin/bash
## #********************************************************************
#Author: xiangzheng
#QQ: 767483070
#Date: 2022-03-24
#FileName: install_harbor.sh
#URL: https://www.xiangzheng.vip
#Email: rootroot25@163.com
#Description: The test script
#Copyright (C): 2022 All rights reserved
#********************************************************************
#需将 docker-compose 和 harbor 文件放到和此脚本同级的目录下
DOCKER_COMPOSE_VERSION="2.3.3"
HARBOR_HOSTNAME="harbor.xiangzheng.vip"
HARBOR_ADMIN_PASSWORD="666666"
HARBOR_VERSION="2.3.5"
docker --version &> /dev/null || { echo "docker未安装 退出" ; exit; }
apt -y install python3
#dnf -y install python3
install_docker-compose(){
chmod +x docker-compose-linux-x86_64
mv docker-compose-linux-x86_64 /usr/bin/docker-compose
docker-compose --version &> /dev/null
if [ $? -eq 0 ];then
echo "docker-compose 安装完成" ; sleep 3
else
echo "docker-compose 安装失败 退出" ; exit 3
fi
}
install_harbor(){
mkdir -p /apps && tar xf harbor-offline-installer-v${HARBOR_VERSION}.tgz -C /apps/
mv /apps/harbor/harbor.yml.tmpl /apps/harbor/harbor.yml
sed -ri.bak "s|(hostname: )(.*)|\1${HARBOR_HOSTNAME}|" /apps/harbor/harbor.yml
sed -ri "s|(harbor_admin_password: )(.*)|\1${HARBOR_ADMIN_PASSWORD}|" /apps/harbor/harbor.yml
sed -ri 's|^(https:)|#\1|' /apps/harbor/harbor.yml
sed -ri 's|(.*)(port: 443)|#\1\2|' /apps/harbor/harbor.yml
sed -ri 's|(.*)(certificate: .*)|#\1\2|' /apps/harbor/harbor.yml
sed -ri 's|(.*)(private_key: .*)|#\1\2|' /apps/harbor/harbor.yml
/apps/harbor/install.sh
cat > /lib/systemd/system/harbor.service <<EOF
[Unit]
Description=Harbor
Requires=docker.service
After=docker.service systemd-networkd.service systemd-resolved.service
Documentation=http://github.com/vmware/harbor
[Service]
Type=simple
Restart=on-failure
RestartSec=5
ExecStart=/usr/bin/docker-compose -f /apps/harbor/docker-compose.yml up
ExecStop=/usr/bin/docker-compose -f /apps/harbor/docker-compose.yml down
ExecReload=/bin/kill -s HUP \$MAINPID
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now harbor.service
systemctl is-active harbor.service &> /dev/null && echo "harbor 安装成功" || echo "harbor 安装失败"
}
install_docker-compose
install_harbor安装 Docker
#!/bin/bash
## #********************************************************************
#Author: xiangzheng
#QQ: 767483070
#Date: 2022-06-15
#FileName: init_docker.sh
#URL: https://www.xiangzheng.vip
#Email: rootroot25@163.com
#Description: 针对 Ubuntu 或 centos 一键安装docker
#Copyright (C): 2022 All rights reserved
#********************************************************************
docker --version &> /dev/null && { echo "docker已经安装 退出" ; exit; }
install_docker_for_ubuntu(){
apt-get -y install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu/ \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
# 可指定安装版本
apt -y install docker-ce=5:20.10.16~3-0~ubuntu-focal docker-ce-cli=5:20.10.16~3-0~ubuntu-focal
#apt -y install docker-ce=5:19.03.15~3-0~ubuntu-focal docker-ce-cli=5:19.03.15~3-0~ubuntu-focal
systemctl is-active docker &>/dev/null && echo "docker安装成功" || { echo "docker安装失败 退出" ; exit; }
}
install_docker_for_centos(){
. /etc/init.d/functions
yum install -y yum-utils
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo \
&& action "docker-ce.repo文件下载成功" || { action "docker-ce.repo文件下载失败 退出" false ; exit; }
mkdir -p /etc/docker/
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://jqm0rnhf.mirror.aliyuncs.com"]
}
EOF
action "docker加速准备完成"
## 可指定安装版本
yum install -y docker-ce-20.10.10 docker-ce-cli-20.10.10 containerd.io
systemctl enable --now docker
systemctl is-active docker &>/dev/null && action "docker安装成功" || action "docker安装失败" false ; exit;
}
#install_docker_for_ubuntu
install_docker_for_centos扫描网段
-c1表示发送一次 ping 请求并等待回复,然后退出程序。即只发送一个 ICMP 包。-W1表示设置等待回复的超时时间为 1 秒。如果在 1 秒内没有接收到回复,那么程序将退出。
扫描单个网段
#!/bin/bash
NET=172.16.0
for IP in {1..254};do
{
ping -c1 -W1 $NET.$IP &> /dev/null && echo "$NET.$IP is online"
}&
done
wait扫描多个网段
#!/bin/bash
NET1=172.16.10
NET2=172.16.20
NET3=172.16.30
for IP in {1..254};do
{
ping -c1 -W1 $NET1.$IP &> /dev/null && echo "$NET1.$IP is online";\
ping -c1 -W1 $NET2.$IP &> /dev/null && echo "$NET2.$IP is online";\
ping -c1 -W1 $NET3.$IP &> /dev/null && echo "$NET2.$IP is online"
}&
done
wait扫描部分IP
- 创建IP列表文件,下面的脚本通过位置变量传参,因此文件名任意
## vim ip_list.txt
172.16.20.1
172.16.20.200
172.16.20.201
172.16.20.180
172.16.20.181
172.16.20.222
172.16.20.223
172.16.10.1
172.16.10.2
172.16.30.199
172.16.30.200
172.16.30.201- scan_ip.sh
#!/bin/bash
IP_LIST_FILE="$1"
while read -r IP
do
{
ping -c1 -W1 $IP &> /dev/null && echo "$IP is online"
}&
done < "${IP_LIST_FILE}"
wait- 执行测试
## ./scan_ip.sh /data/scripts/ip_list.txt
172.16.20.180 is online
172.16.20.181 is onlineFTP上传和下载文件
交互式
- ftp_upload_download.sh
#!/bin/bash
### 匿名登录 ###
PROXY_HOST="172.16.66.208"
PROXY_PORT="12081"
FTP_HOST="172.16.66.202"
#FTP_HOST="gyh7lb7om5wvxsifwefq675za3m73spilf5lebaum5kjc652gaugikad.onion"
FTP_USER="anonymous"
FTP_PASS="123"
SUB_DIR="testdir/"
### 非匿名登录 ###
#PROXY_HOST="172.16.66.208"
#PROXY_PORT="12081"
#FTP_HOST="172.16.66.213"
#FTP_USER="ftpuser"
#FTP_PASS="ftppass"
function upload (){
## 读取要上传的文件
read -p "Please enter the file to upload to ${FTP_HOST}: " LOCAL_FILE
## 上传文件
echo "Uploading file..."
if [[ -n "${PROXY_HOST}" && -n "${PROXY_PORT}" ]]; then
# 使用代理服务器
curl --socks5 ${PROXY_HOST}:${PROXY_PORT} \
--upload-file ${LOCAL_FILE} \
ftp://${FTP_HOST}/${SUB_DIR} \
--user ${FTP_USER}:${FTP_PASS} \
-s
else
# 不使用代理服务器
curl --upload-file ${LOCAL_FILE} \
ftp://${FTP_HOST}/${SUB_DIR} \
--user ${FTP_USER}:${FTP_PASS} \
-s
fi
echo "File uploaded."
}
function download (){
## 读取要下载的文件
read -p "Please enter the file to download from ${FTP_HOST}: " REMOTE_FILE
## 下载文件
echo "Downloading file..."
if [[ -n "${PROXY_HOST}" && -n "${PROXY_PORT}" ]]; then
# 使用代理服务器
curl --socks5 "${PROXY_HOST}:${PROXY_PORT}" \
--user "${FTP_USER}:${FTP_PASS}" \
"ftp://${FTP_HOST}/${SUB_DIR}${REMOTE_FILE}" \
-o ${REMOTE_FILE} \
-s
else
# 不使用代理服务器
curl --user "${FTP_USER}:${FTP_PASS}" \
"ftp://${FTP_HOST}/${SUB_DIR}${REMOTE_FILE}" \
-o ${REMOTE_FILE} \
-s
fi
echo "File downloaded."
}
cat <<EOF
1) upload
2) download
3) exit
EOF
read -p "please enter a number (1-3): " NUM
case ${NUM} in
1)
upload
;;
2)
download
;;
*)
echo exit && exit 3
esac非互式
- ftp_upload_download.sh
#!/bin/bash
PROXY_HOST=""
PROXY_PORT=""
FTP_HOST=""
FTP_USER=""
FTP_PASS=""
SUB_DIR=""
show_help () {
cat <<EOF
Usage:
$0 [option...]
Options:
-u, --upload upload mode
-d, --download download mode
-h, --host <string> FTP server address [required]
-a, --username <string> non-anonymous login username
-p, --password <string> non-anonymous login password
-s, --subdir <string> sub directory on FTP server
-x, --proxy <string> proxy server <host>:<port>
-f, --file <string> filename to upload or download [required for upload/download modes]
Examples:
$0 -u -h 172.16.66.202 -f test.txt
$0 -d -h 172.16.66.213 -a ftpuser -p 'myftppass' -s testdir/ -f tor.jpg
$0 -u -h gyh7lb7om5wvxsifwefq675za3m73spilf5lebaum5kjc652gaugikad.onion -x 172.16.66.208:12081 -f secrets.txt
EOF
}
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
show_help
exit 0
fi
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-u|--upload) # upload mode
MODE="upload"; shift
;;
-d|--download) # download mode
MODE="download"; shift
;;
-h|--host) # FTP server address
FTP_HOST="$2"; shift 2
;;
-a|--username) # non-anonymous login username
FTP_USER="$2"; shift 2
;;
-p|--password) # non-anonymous login password
FTP_PASS="$2"; shift 2
;;
-s|--subdir) # sub directory on FTP server
SUB_DIR="$2/"; shift 2
;;
-x|--proxy) # proxy server <host>:<port>
PROXY="$2"; shift 2
;;
-f|--file) # filename to upload or download
FILE="$2"; shift 2
;;
-*) # unknown options
echo -e "Unknown option: $1\nTry '$0 --help' for more information." >&2; exit 1
;;
*) # positional arguments
echo -e "Unknown argument: $1\nTry '$0 --help' for more information." >&2; exit 1
;;
esac
done
## make sure required options are set
if [[ -z "$FTP_HOST" ]]; then
echo "FTP host not defined! Use -h or --host option to specify." >&2
echo "Try '$0 --help' for more information." >&2
exit 1
fi
if [[ "$MODE" == "upload" ]]; then
if [[ -z "$FILE" ]]; then
echo "No file specified for upload! Use -f or --file option to specify." >&2
echo "Try '$0 --help' for more information." >&2
exit 1
fi
# upload file
if [[ -n "$PROXY" ]]; then
# use proxy server
curl --socks5-hostname "$PROXY" \
--upload-file "$FILE" \
ftp://"$FTP_HOST"/"$SUB_DIR" \
--user "$FTP_USER:$FTP_PASS" #-s
else
# no proxy
curl --upload-file "$FILE" \
ftp://"$FTP_HOST"/"$SUB_DIR" \
--user "$FTP_USER:$FTP_PASS" #-s
fi
elif [[ "$MODE" == "download" ]]; then
if [[ -z "$FILE" ]]; then
echo "No file specified for download! Use -f or --file option to specify." >&2
echo "Try '$0 --help' for more information." >&2
exit 1
fi
# download file
if [[ -n "$PROXY" ]]; then
# use proxy server
curl --socks5-hostname "$PROXY" \
--user "$FTP_USER:$FTP_PASS" \
"ftp://$FTP_HOST/$SUB_DIR$FILE" \
-o "$FILE" #-s
else
# no proxy
curl --user \
"$FTP_USER:$FTP_PASS" \
"ftp://$FTP_HOST/$SUB_DIR$FILE" \
-o "$FILE" #-s
fi
fi测试文档
- 匿名用户
## 匿名用户通过代理上传
./ftp_upload_download.sh -u -h 172.16.66.202 -x 172.16.66.208:12081 -f fstab -s testdir/ -a anonymous -p 123
./ftp_upload_download.sh -u -h gyh7lb7om5wvxsifwefq675za3m73spilf5lebaum5kjc652gaugikad.onion -x 172.16.66.208:12081 -f fstab -s testdir/ -a anonymous -p 123
## 匿名用户通过代理下传
./ftp_upload_download.sh -d -h 172.16.66.202 -x 172.16.66.208:12081 -f fstab -s testdir/ -a anonymous -p 123
./ftp_upload_download.sh -d -h gyh7lb7om5wvxsifwefq675za3m73spilf5lebaum5kjc652gaugikad.onion -x 172.16.66.208:12081 -f fstab -s testdir/ -a anonymous -p 123
## 匿名用户不通过代理上传
./ftp_upload_download.sh -u -h 172.16.66.202 -f fstab -s testdir/ -a anonymous -p 123
## 匿名用户不通过代理下载
./ftp_upload_download.sh -d -h 172.16.66.202 -f fstab -s testdir/ -a anonymous -p 123- 非匿名用户
## 非匿名用户通过代理上传
./ftp_upload_download.sh -u -h 172.16.66.213 -x 172.16.66.208:12081 -f fstab -a ftpuser -p ftppass
./ftp_upload_download.sh -u -h gyh7lb7om5wvxsifwefq675za3m73spilf5lebaum5kjc652gaugikad.onion -x 172.16.66.208:12081 -f fstab -a ftpuser -p ftppass
## 非匿名用户通过代理下传
./ftp_upload_download.sh -d -h 172.16.66.213 -x 172.16.66.208:12081 -f fstab -a ftpuser -p ftppass
## 非匿名用户不通过代理上传
./ftp_upload_download.sh -u -h 172.16.66.213 -f fstab -a ftpuser -p ftppass
## 非匿名用户不通过代理下载
./ftp_upload_download.sh -d -h 172.16.66.213 -f fstab -a ftpuser -p ftppass1
## http可以访问
curl --socks5-hostname "172.16.66.208:12081" "http://gyh7lb7om5wvxsifwefq675za3m73spilf5lebaum5kjc652gaugikad.onion"
## 好了
curl --socks5-hostname "172.16.66.208:12081" --upload-file fstab ftp://gyh7lb7om5wvxsifwefq675za3m73spilf5lebaum5kjc652gaugikad.onion/testdir/ --user anonymous:111
./ftp_upload_download.sh -u -h gyh7lb7om5wvxsifwefq675za3m73spilf5lebaum5kjc652gaugikad.onion -x 172.16.66.208:12081 -f fstab -s testdir/ -a anonymous -p 123一键安装 Docker
docker_install.sh
#!/bin/bash
ubuntu_function() {
local docker_version="5:20.10.24~3-0~ubuntu-*"
if command -v docker &>/dev/null; then
echo "Docker is already installed."
else
apt-get update
apt-get -y install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
apt-get -y update
apt-get -y install docker-ce=${docker_version}
configure_docker_accelerator
fi
}
centos_function() {
echo "This is CentOS!"
}
other_function() {
echo "This is another distribution!"
}
configure_docker_accelerator() {
if [ ! -f /etc/docker/daemon.json ]; then
mkdir -p /etc/docker
touch /etc/docker/daemon.json
fi
echo '{
"registry-mirrors": ["https://jqm0rnhf.mirror.aliyuncs.com"]
}' | sudo tee /etc/docker/daemon.json > /dev/null
systemctl restart docker
echo "Docker image accelerator configured successfully."
}
if [ -f /etc/os-release ]; then
source /etc/os-release
case "$ID" in
ubuntu)
ubuntu_function
;;
centos)
centos_function
;;
*)
other_function
;;
esac
else
echo "Unable to determine the Linux distribution."
fi批量上传镜像
方法一
#!/bin/bash
## 定义镜像仓库地址和名称
repository="172.16.0.120:30002/darknet-target"
## 获取镜像列表
images=(
$(docker images | grep www | grep -Ev "(k8s|ubuntu)" | awk '{print $1 ":" $2 }')
)
## 循环处理每个镜像
for image in "${images[@]}"
do
# 添加标签
docker tag "$image" "$repository/$(basename "$image")"
# 推送到镜像仓库
docker push "$repository/$(basename "$image")"
done- 此脚本将遍历
images数组中定义的镜像列表,并为每个镜像添加标签,然后将其推送到指定的镜像仓库。脚本中的repository变量定义了目标镜像仓库的地址和名称,你可以根据需要进行修改。 - 请注意,你需要在运行脚本之前已经登录到目标镜像仓库。如果尚未登录,请在脚本中添加适当的
docker login命令以进行登录。
方法二
#/bin/bash
IP="10.0.0.10:30002"
REPO="/tor-target"
SOURCE_IMAGES=$(docker images | grep "$REPO" | awk '{print $1 ":" $2}')
for IMAGE in $SOURCE_IMAGES
do
#echo "docker tag $IMAGE ${IP}${REPO}/$(basename ${IMAGE})"
#echo "docker push ${IP}${REPO}/$(basename ${IMAGE})"
docker tag $IMAGE ${IP}${REPO}/$(basename ${IMAGE})
docker push ${IP}${REPO}/$(basename ${IMAGE})
#docker rmi ${IP}${REPO}/$(basename ${IMAGE})
done遇到的问题
unauthorized: unauthorized to access repository: darknet-target/tor_da, action: push: unauthorized to access repository: darknet-target/tor_da, action: push
这个错误表示你的用户没有足够的权限来推送镜像到指定的镜像仓库。为了解决这个问题,你可以尝试以下几个步骤:
-
确保你已经使用正确的凭据登录到目标镜像仓库。运行以下命令登录到镜像仓库:
docker login 172.16.0.120:30002在登录时,你需要提供正确的用户名和密码或其他凭据。
-
检查你登录的用户是否具有推送(push)镜像到指定仓库的权限。你可能需要联系仓库管理员或拥有适当权限的用户,以获得推送镜像的权限。
-
验证目标镜像仓库的名称是否正确。确保在上传时指定了正确的镜像仓库名称和路径。可以通过运行以下命令检查已登录用户的仓库列表:
docker repository ls -
如果你使用的是私有镜像仓库,并且你在
docker push命令中使用了带有仓库名称的标签,请确保仓库名称正确且与你的仓库设置一致。有时候,这个错误可能是由于标签中的仓库名称拼写错误或者与你的仓库设置不匹配所导致的。
请按照上述步骤检查和修复相关问题,并确保你具有足够的权限来推送镜像到指定的镜像仓库。如有需要,请联系你的镜像仓库管理员获取更多帮助和支持。
批量构建和推送镜像
#!/bin/bash
function login() {
echo "start login harbor"
docker login -u $harbor_username -p $harbor_password $harbor
}
function build() {
local role=$1
docker build -f "Dockerfile_${role}" -t "${harbor}/${respository}/${role}:${version}" .
}
function push() {
local role=$1
docker push "${harbor}/${respository}/${role}:${version}"
}
function main() {
login
for role in "${roles[@]}"
do
#build ${role}
push ${role}
done
}
harbor="172.16.0.120:30002"
harbor_username="admin"
harbor_password="Harbor12345"
respository="tor-target"
roles=("da" "relay" "exit" "client" "onion")
version="4.7.13"
main在 Bash 脚本中,local 关键字用于声明一个本地变量,这意味着该变量只在当前函数的作用域内有效。在这种情况下,local role=$1 表示将作为参数传递给函数的第一个参数赋值给本地变量 role。
在这个脚本中,push 函数被定义为接受一个参数 role。使用 local 关键字声明的变量仅在 push 函数内部可见,这样做的目的是确保在函数执行期间不会意外修改或覆盖脚本中其他地方定义的全局变量 role。
制作以及调试镜像
make_image.sh
#!/bin/bash
IMAGE='systemwire:v1.0'
#NAME='systemwire'
NAME='test'
build_image() {
docker build -t $IMAGE .
}
run_container() {
#docker run -d -p 5000:5000 --name test --rm $IMAGE
docker run -d --name $NAME --rm $IMAGE
}
enter_container() {
docker exec -it test bash
}
stop_container() {
docker stop test
}
case "$1" in
build)
build_image
;;
run)
run_container
;;
stop)
stop_container
;;
exec)
enter_container
;;
*)
echo "Usage: $0 {build|run|exec|stop}"
esac查看实时网络流量
#!/bin/bash
while [ True ];do
i=0
for eth in $(cat /proc/net/dev | sed -e '1,2d'|cut -d: -f1);do
RX[$i]=$(cat /proc/net/dev | grep $eth | tr : " " | awk '{print $2}')
TX[$i]=$(cat /proc/net/dev | grep $eth | tr : " " | awk '{print $10}')
let i=$i+1
done
sleep 1
clear
i=0
for eth in $(cat /proc/net/dev | sed -e '1,2d'|cut -d: -f1);do
RXnext[$i]=$(cat /proc/net/dev | grep $eth | tr : " " | awk '{print $2}')
TXnext[$i]=$(cat /proc/net/dev | grep $eth | tr : " " | awk '{print $10}')
let i=$i+1
done
i=0
echo -e "\t RX `date +%k:%M:%S` TX"
for eth in $(cat /proc/net/dev | sed -e '1,2d'|cut -d: -f1);do
RX=$((${RXnext[$i]}-${RX[$i]}))
TX=$((${TXnext[$i]}-${TX[$i]}))
if [[ $RX -lt 1024 ]];then
RX="${RX}B/s"
elif [[ $RX -gt 1048576 ]];then
RX=$(echo $RX | awk '{print $1/1048576 "MB/s"}')
else
RX=$(echo $RX | awk '{print $1/1024 "KB/s"}')
fi
if [[ $TX -lt 1024 ]];then
TX="${TX}B/s"
elif [[ $TX -gt 1048576 ]];then
TX=$(echo $TX | awk '{print $1/1048576 "MB/s"}')
else
TX=$(echo $TX | awk '{print $1/1024 "KB/s"}')
fi
echo -e "$eth \t $RX $TX "
let i=$i+1
done
done离线安装pip与netmiko
#!/bin/bash
## 目录路径
PIP_SCRIPT="get-pip.py"
PIP_PACKAGE_DIR="pip_offline"
NETMIKO_PACKAGE_DIR="netmiko_package"
## 函数:检查命令是否存在
command_exists() {
command -v "$1" >/dev/null 2>&1
}
## 函数:安装pip
install_pip() {
if [ -f "$PIP_SCRIPT" ] && [ -d "$PIP_PACKAGE_DIR" ]; then
python2 "$PIP_SCRIPT" --no-index --find-links="$PIP_PACKAGE_DIR"
else
echo "$PIP_SCRIPT or $PIP_PACKAGE_DIR not found."
exit 1
fi
}
## 函数:安装netmiko
install_netmiko() {
if [ -d "$NETMIKO_PACKAGE_DIR" ]; then
pip2 install --no-index --find-links="$NETMIKO_PACKAGE_DIR" netmiko==2.4.2
else
echo "$NETMIKO_PACKAGE_DIR directory not found."
exit 1
fi
}
## 检查并安装pip
if command_exists pip; then
echo "pip is already installed."
else
echo "pip is not installed. Installing pip..."
install_pip
fi
## 检查并安装netmiko
if python2 -c "import netmiko" &>/dev/null; then
echo "netmiko is already installed."
else
echo "netmiko is not installed. Installing netmiko..."
install_netmiko
fi
echo "Setup completed."批量域名解析测试
check_domains.sh
#!/bin/bash
## 检查是否提供了文件
if [ $# -eq 0 ]; then
echo "请提供一个包含域名的文件作为参数"
exit 1
fi
## 读取域名列表文件
domain_file=$1
## 检查文件是否存在
if [ ! -f "$domain_file" ]; then
echo "文件 $domain_file 不存在"
exit 1
fi
## 遍历域名列表
while IFS= read -r domain; do
# 跳过空行和以#开头的注释行
if [[ -z "$domain" || "$domain" =~ ^# ]]; then
continue
fi
# 使用nslookup测试域名解析并提取IP地址
result=$(nslookup "$domain" 2>/dev/null)
# 根据nslookup返回的状态码判断是否能解析
if [ $? -eq 0 ]; then
# 提取IP地址
ip=$(echo "$result" | awk '/^Address: / {print $2}')
echo "$domain 能被解析,IP地址: $ip"
#else
# echo "$domain 无法解析"
fi
done < "$domain_file"domains.txt
ftp.harbin2025.com
repo.harbin2025.com
docs.harbin2025.com
alerts.harbin2025.com
results.harbin2025.com
standings.harbin2025.com
refreshments.harbin2025.com
streaming.harbin2025.com
liveblog.harbin2025.com
photo.harbin2025.com
admin.harbin2025.com
test.harbin2025.com
pay.harbin2025.com
dev.harbin2025.com
db.harbin2025.com
download.harbin2025.com
backup.harbin2025.com
devops.harbin2025.com
chat.harbin2025.com—
要批量测试一批域名是否能被解析,你可以编写一个简单的Shell脚本,利用nslookup或dig工具进行DNS查询。下面是一个使用nslookup工具的示例脚本。
脚本内容
#!/bin/bash
## 检查是否提供了文件
if [ $# -eq 0 ]; then
echo "请提供一个包含域名的文件作为参数"
exit 1
fi
## 读取域名列表文件
domain_file=$1
## 检查文件是否存在
if [ ! -f "$domain_file" ]; then
echo "文件 $domain_file 不存在"
exit 1
fi
## 遍历域名列表
while IFS= read -r domain; do
# 跳过空行和以#开头的注释行
if [[ -z "$domain" || "$domain" =~ ^# ]]; then
continue
fi
# 使用nslookup测试域名解析
nslookup "$domain" > /dev/null 2>&1
# 根据nslookup返回的状态码判断是否能解析
if [ $? -eq 0 ]; then
echo "$domain 能被解析"
else
echo "$domain 无法解析"
fi
done < "$domain_file"使用说明
-
将域名列表保存在一个文本文件中(例如
domains.txt),每个域名占一行。- 文件示例:
google.com example.com nonexistdomain.xyz
- 文件示例:
-
将上述脚本保存为文件(例如
check_domains.sh)。 -
赋予脚本执行权限:
chmod +x check_domains.sh -
运行脚本并传递域名文件作为参数:
./check_domains.sh domains.txt
脚本工作原理
- 脚本首先检查是否传入了域名文件作为参数。
- 它会逐行读取域名列表,跳过空行和注释(以
#开头的行)。 - 使用
nslookup工具来检查每个域名是否能够解析。如果nslookup返回成功(状态码为0),则输出该域名可以解析;否则,输出该域名无法解析。
其他注意事项
- 如果你想使用
dig工具,可以将nslookup替换为dig,例如:然后根据返回的结果判断是否能够解析。dig +short "$domain"
这个脚本非常简单且实用,适用于常见的批量域名解析测试场景。如果你有更复杂的需求,可以根据需要进一步修改脚本。
nmap扫描网段
好的,使用 nmap 来扫描一个网段中的主机是否开放 22 端口会更高效且功能更强大。下面是一个使用 nmap 的 Shell 脚本示例:
脚本:check_ssh_ports_with_nmap.sh
#!/bin/bash
## 设置要扫描的网段(可以根据需求修改)
network="192.168.1" # 例如,192.168.1.0/24网段
## 扫描的端口
port=22
## 扫描网段中的主机,使用 nmap 检查 22 端口是否开放
nmap -p $port --open ${network}.0/24 -oG - | awk '/22\/open/ {print $2 " 的 22 端口开放"}'说明:
-
network="192.168.1":扫描的网段。你可以根据需要修改成你自己想扫描的网段,如10.0.0或192.168.0等。 -
port=22:指定要检查的端口,默认是22,即 SSH 端口。 -
nmap -p $port --open ${network}.0/24:使用
nmap扫描指定网段的 IP,检测端口是否开放:
-p $port:指定扫描的端口(这里是 22)。--open:只显示开放的端口。${network}.0/24:扫描整个192.168.1.0/24网段,检查该网段中哪些主机的 22 端口开放。
-
-oG -:将nmap输出以 “grepable” 格式输出,便于后续处理。 -
awk '/22\/open/ {print $2 " 的 22 端口开放"}':使用awk处理nmap输出,只打印开放了 22 端口的主机 IP。
执行:
- 将脚本保存为一个文件,例如
check_ssh_ports_with_nmap.sh。 - 给脚本执行权限:
chmod +x check_ssh_ports_with_nmap.sh。 - 执行脚本:
./check_ssh_ports_with_nmap.sh。
示例输出:
192.168.1.5 的 22 端口开放
192.168.1.20 的 22 端口开放
192.168.1.45 的 22 端口开放
安装 nmap:
-
如果你的系统没有安装
nmap,可以通过以下命令安装:
- 在 Ubuntu/Debian 上:
sudo apt-get install nmap - 在 CentOS/RHEL 上:
sudo yum install nmap - 在 macOS 上:
brew install nmap
- 在 Ubuntu/Debian 上:
说明:
- 使用
nmap来扫描比手动使用nc更为高效,尤其是在大规模网络中,因为nmap会并行扫描多个目标。 - 如果你需要扫描特定的 IP 范围,可以将网段替换为具体的 IP 地址,例如:
192.168.1.1-254。
这样你就能更方便、高效地扫描网段内哪些机器的 22 端口开放了。