Bash脚本实用示例与操作指南
1. 权威DNS查询脚本
1.1 脚本概述
权威DNS查询脚本借助
dig
命令开展DNS查询,能够绕过本地DNS缓存服务器。该脚本的独特之处在于,它依据自身名称来明确要查询的DNS记录类型。例如,若脚本名为
a
,则查询DNS A记录;若名为
soa
,则查询DNS SOA记录。特殊的
ptr
名称可将IPv4地址转换为合适的
in-addr.arpa
形式进行实际查询。
1.2 脚本代码
#!/bin/bash
#----------------------------------------------------------------
# Copyright © 2006 - Philip Howard - All rights reserved
#
# script a, aaaa, cname, mx, ns, ptr, soa, txt
#
# purpose Perform direct DNS lookups for authoritative DNS
# data. This lookup bypasses the local DNS cache
# server.
#
# syntax a [ names ... ]
# aaaa [ names ... ]
# any [ names ... ]
# cname [ names ... ]
# mx [ names ... ]
# ns [ names ... ]
# ptr [ names ... ]
# soa [ names ... ]
# txt [ names ... ]
#
# author Philip Howard
#----------------------------------------------------------------
# For use with ptr query.
function inaddr {
awk -F. '{print $4 "." $3 "." $2 "." $1 ".in-addr.arpa.";}'
}
query_type=$( exec basename "${0}" )
# Get and query for each host.
for hostname in "$@" ; do
if [[ "${query_type}" == ptr ]] ; then
# A typical scripting trick: when a case can begin
# with a numeral, place a dummy character such as x in
# front because the case syntax expects an alphanumeric
# character.
case "x${hostname}y" in
( x[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*y )
hostname=$( echo "${hostname}" | inaddr )
;;
( * )
;;
esac
fi
# Execute the query.
dig +trace +noall +answer "${query_type}" "${hostname}" | \
egrep "^${hostname}"
done
exit
1.3 操作步骤
-
复制上述代码到一个文件中,例如
dns_lookup.sh。 -
根据需要查询的DNS记录类型,创建该脚本的副本或硬链接、符号链接,如
ln -s dns_lookup.sh a创建查询A记录的链接。 -
执行脚本,传入要查询的主机名,如
./a example.com。
2. 跨Shell会话文件传输脚本
2.1 脚本概述
此脚本可借助每个系统上的shell会话,将文件或包含所有子目录的文件目录从一个系统传至另一个系统。它通过在前台创建
rsync
守护进程来发送指定的文件或目录,并展示几种不同形式的
rsync
命令,用于在接收系统上接收文件或目录。
2.2 脚本代码
#!/bin/bash
#----------------------------------------------------------------
# Copyright © 2006 - Philip Howard - All rights reserved
#
# script rsend
#
# purpose To start an rsync daemon in the shell foreground
# to send a specified directory or file when
# retrieved using one of the rsync command lines
# shown, by pasting it in a shell session on another
# host.
#
# usage rsend [options] directory | file
#
# options -c include checksum in the rsync command lines
# -d change daemon to the specified directory
# -n include dryrun in the rsync command lines
# -p use the specified port number, else random
# -s include sparse in the rsync command lines
# -u user to run as, if started as root
# -v show extra information
#
# author Philip Howard
#----------------------------------------------------------------
umask 022
hostname=$( exec hostname -f )
whoami=$( exec whoami )
uid="${whoami}"
#----------------------------------------------------------------
# Set defaults.
#----------------------------------------------------------------
checksum=""
delete=""
delmsg=""
dryrun=""
padding="-------"
port=""
sparse=""
verbose=""
bar1="--------------------------"
bar1="#${bar1}${bar1}${bar1}"
bar2="##########################"
bar2="#${bar2}${bar2}${bar2}"
#----------------------------------------------------------------
# Include paths for ifconfig.
#----------------------------------------------------------------
export PATH="${PATH}:/usr/sbin:/sbin"
#----------------------------------------------------------------
# Scan options.
#----------------------------------------------------------------
while [[ $# -gt 0 && "x${1:0:1}" = "x-" ]]; do
case "x${1}" in
( x-c | x--checksum )
checksum="c"
;;
( x--delete )
delete=" --delete"
delmsg="/delete"
padding=""
;;
( x-d | x--directory )
shift
cd "${1}" || exit 1
;;
( x--directory=* )
cd "${1:12}" || exit 1
;;
( x-n | x--dry-run )
dryrun="n"
;;
( x-p | x--port )
shift
port="${1}"
;;
( x--port=* )
port="${1:7}"
;;
( x-s | x--sparse )
sparse="S"
;;
( x-u | x--user )
shift
uid="${1}"
;;
( x--user=* )
uid="${1:7}"
;;
( x-v | x--verbose )
verbose=1
;;
esac
shift
done
#----------------------------------------------------------------
# Get a random number for a port.
#----------------------------------------------------------------
if [[ -z "${port}" || "${port}" = 0 || "${port}" = . ]]; then
port=$( dd if=/dev/urandom ibs=2 obs=2 count=1 2>/dev/null \
| od -An -tu2 | tr -d ' ' )
port=$[ $port % 16384 ]
port=$[ $port + 12288 ]
fi
#----------------------------------------------------------------
# Make up names for temporary files to be used.
#----------------------------------------------------------------
conffile="/tmp/rsync-${whoami}-${port}-$$.conf"
lockfile="/tmp/rsync-${whoami}-${port}-$$.lock"
#----------------------------------------------------------------
# This function adds quotes to strings that need them.
# Add single quotes if it has one of these: space $ " `
# Add double quotes if it has one of these: '
# Note: not all combinations will work.
#----------------------------------------------------------------
function strquote {
local str
str=$( echo "${1}" | tr -d ' $"`' )
if [[ "${str}" != "${1}" ]]; then
echo "'${1}'"
return
fi
str=$( echo "${1}" | tr -d "'" )
if [[ "${str}" != "${1}" ]]; then
echo '"'"${1}"'"'
return
fi
echo "${1}"
return 0
}
#----------------------------------------------------------------
# Only one name can be handled.
#----------------------------------------------------------------
if [[ $# -gt 1 ]]; then
echo "Only one name (directory or file)" 1>&2
exit 1
elif [[ $# -eq 1 ]]; then
name="${1}"
else
name=$( exec pwd )
fi
#----------------------------------------------------------------
# Set up a temporary config file.
#
# Arguments:
# $1 Directory transferred, or where transfer is starting
# $2 Not used (AO: Should be removed)
# $3 File transferred (if single file specified)
#----------------------------------------------------------------
function configout {
echo "lock file = ${lockfile}"
echo "log file = /dev/stderr"
echo "use chroot = false"
echo "max connections = 32"
echo "socket options = SO_KEEPALIVE"
echo "list = yes"
echo "[.]"
echo "path = ${1}"
echo "read only = yes"
echo "uid = ${uid}"
echo "comment = ${2}"
if [[ -n "${3}" ]]; then
echo "include = **/${3}"
echo "exclude = **"
fi
}
#----------------------------------------------------------------
# Get directory and file.
#----------------------------------------------------------------
if [[ ! -e "${name}" ]]; then
echo "does not exist:" $( strquote "${name}" ) 1>&2
exit 1
elif [[ -d "${name}" ]]; then
p=$( exec dirname "${name}" )
b=$( exec basename "${name}" )
d="${name}"
f=""
r=$( cd "${name}" && exec pwd )
announce="${d}"
rsyncopt="-a${checksum}${dryrun}H${sparse}vz${delete}"
configout "${d}/." "directory:${d}/" >"${conffile}"
elif [[ -f "${name}" ]]; then
p=$( exec dirname "${name}" )
b=$( exec basename "${name}" )
d="${p}"
f="${b}"
r=$( cd "${p}" && exec pwd )
r="${r}/${b}"
announce="${d}/${f}"
rsyncopt="-a${checksum}${dryrun}${sparse}vz"
configout "${d}/." "file:${d}/${f}" >"${conffile}"
elif [[ -L "${name}" ]]; then
p=$( exec dirname "${name}" )
b=$( exec basename "${name}" )
d="${p}"
f="${b}"
r=$( cd "${p}" && exec pwd )
r="${r}/${b}"
announce="${d}/${f}"
rsyncopt="-a${checksum}v"
configout "${d}/." "symlink:${d}/${f}" "${f}" >"${conffile}"
fi
#----------------------------------------------------------------
# Show config file if verbose is requested.
#----------------------------------------------------------------
if [[ -n "${verbose}" ]]; then
echo "${bar2}"
ls -ld "${conffile}"
echo "${bar2}"
cat "${conffile}"
fi
#----------------------------------------------------------------
# This function outputs example receive commands.
#----------------------------------------------------------------
function showrsync {
echo -n "rsync ${rsyncopt} "
if [[ -n "${oldfmt}" ]]; then
echo "--port=${port}" $( strquote "${1}::${2}" ) $( strquote "${3}" )
else
echo $( strquote "rsync://${1}:${port}/${2}" ) $( strquote "${3}" )
fi
return
}
#----------------------------------------------------------------
# These functions show rsync commands for hostname and IP address.
#----------------------------------------------------------------
function getip {
case $( exec uname -s ) in
( SunOS )
netstat -i -n | awk '{print $4;}'
;;
( Linux )
ifconfig -a | awk '{if($1=="inet")print substr($2,6);}'
;;
( * )
netstat -i -n | awk '{print $4;}'
;;
esac
return
}
function ipaddr {
getip \
| egrep '^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$' \
| egrep -v '^0\.|^127\.' \
| head -2 \
| while read ipv4 more ; do
showrsync "${ipv4}" "$@"
done
return
}
function showcmd {
ipaddr "${2}" "${3}"
showrsync "${1}" "${2}" "${3}"
return
}
#----------------------------------------------------------------
# Announce the shell commands to receive this data.
#----------------------------------------------------------------
echo "${bar2}"
echo "# sending ${announce}"
echo "# paste ONE of these commands in a remote shell to receive"
if [[ -d "${name}" ]]; then
echo "${bar1}"
showcmd "${hostname}" . .
echo "${bar1}"
showcmd "${hostname}" . "${b}"
if [[ "${d}" != "${b}" && "${d}" != "${r}" ]]; then
echo "${bar1}"
showcmd "${hostname}" . "${d}"
fi
echo "${bar1}"
showcmd "${hostname}" . "${r}"
else
echo "${bar1}"
showcmd "${hostname}" "./${f}" "${b}"
s=$( exec basename "${d}" )
s="${s}/${f}"
if [[ "${s}" != "${b}" ]]; then
echo "${bar1}"
showcmd "${hostname}" "./${f}" "${s}"
fi
if [[ "${name}" != "${b}" \
&& "${name}" != "${s}" \
&& "${name}" != "${r}" ]]; then
echo "${bar1}"
showcmd "${hostname}" "./${f}" "${name}"
fi
echo "${bar1}"
showcmd "${hostname}" "./${f}" "${r}"
fi
echo "${bar1}"
echo "# press ^C here when done"
echo "${bar2}"
#----------------------------------------------------------------
# Start rsync in daemon mode.
#----------------------------------------------------------------
s="DONE"
trap 's="SIGINT ... DONE"' INT
trap 's="SIGTERM ... DONE"' TERM
rsync --daemon --no-detach "--config=${conffile}" "--port=${port}"
rm -f "${conffile}" "${lockfile}"
echo "${s}"
2.3 操作步骤
-
复制上述代码到一个文件中,例如
rsend.sh。 -
在发送系统上运行脚本,可指定选项和要发送的文件或目录,如
./rsend.sh -p 12345 /path/to/file。 -
脚本会输出一些示例的
rsync命令,根据能访问发送系统的IP地址或主机名,以及接收系统上文件或目录的存储目标位置,选择合适的命令。 - 将选中的命令复制到接收系统的shell中执行,完成文件或目录的接收。
-
传输完成后,在发送系统的shell窗口中按
Ctrl - C停止守护进程。
2.4 注意事项
-
该脚本无安全机制,任何能访问其监听地址和端口号的人都可获取传输的数据,因此请勿用于传输机密或敏感数据,可尝试使用
scp或sftp。 -
确保发送系统为其使用的端口号开放网络访问,可使用
-p选项指定端口号。若防火墙规则仅允许连接一个或几个端口,必须使用这些端口号。
3. SSH与Screen集成脚本
3.1 脚本概述
此脚本可通过一个命令建立SSH连接并启动一个命名的
screen
会话,在处理多个服务器时,能实现更快速的连接和断开操作。它的使用方式与
ssh
命令类似,但扩展了指定远程会话用户名和主机名的语法,还可包含会话名。
3.2 脚本代码
#!/usr/bin/env bash
#----------------------------------------------------------------
# Copyright © 2006 - Philip Howard - All rights reserved
#
# command ss (secure screen)
#
# purpose Establish a screen based background shell session
# via secure shell communications.
#
# syntax ss [options] session/username@hostname
# ss [options] session@username@hostname
# ss [options] username@hostname/session
# ss [options] username@hostname session
#
# options -h hostname
# -h=hostname
# -i identity
# -i=identity
# -l loginuser
# -l=loginuser
# -m Multi-display mode
# -p portnum
# -p=portnum
# -s session
# -s=session
# -t Use tty allocation (default)
# -T Do NOT use tty allocation
# -4 Use IPv4 (default)
# -6 Use IPv6
# -46 | -64 Use either IPv6 or IPv4
#
# requirements The local system must have the OpenSSH package
# installed. The remote system must have the
# OpenSSH package installed and have the sshd
# daemon running. It must also have the screen(1)
# program installed. Configuring a .screenrc
# file on each system is recommended.
#
# note The environment variable SESSION_NAME will be set
# in the session created under the screen command
# for potential use by other scripts.
#
# author Philip Howard
#----------------------------------------------------------------
whoami=$( exec whoami )
hostname=$( exec hostname )
h=""
i=( )
m=""
p=( )
s=''
t=( -t )
u="${whoami}"
v=( -4 )
#----------------------------------------------------------------
# Parse options and arguments.
#----------------------------------------------------------------
while [[ $# -gt 0 ]]; do
case "x${1}" in
( x*/*@* )
# Example: session1/lisa@centrhub
u=$( echo "x${1}" | cut -d @ -f 1 )
u="${u:1}"
s=$( echo "x${u}" | cut -d / -f 2 )
u=$( echo "x${u}" | cut -d / -f 1 )
u="${u:1}"
h=$( echo "x${1}" | cut -d @ -f 2 )
shift
break
;;
( x*@*/* )
# Example: lisa@centrhub/session1
u=$( echo "x${1}" | cut -d @ -f 1 )
u="${u:1}"
h=$( echo "x${1}" | cut -d @ -f 2 )
s=$( echo "x${h}" | cut -d / -f 2 )
h=$( echo "x${h}" | cut -d / -f 1 )
h="${h:1}"
shift
break
;;
( x*@*@* )
# Example: session1@lisa@centrhub
s=$( echo "x${1}" | cut -d @ -f 1 )
s="${s:1}"
u=$( echo "x${1}" | cut -d @ -f 2 )
h=$( echo "x${1}" | cut -d @ -f 3 )
shift
break
;;
( x*@* )
# Example: lisa@centrhub
u=$( echo "x${1}" | cut -d @ -f 1 )
u="${u:1}"
h=$( echo "x${1}" | cut -d @ -f 2 )
# Next argument should be session name.
shift
if [[ $# -gt 0 ]]; then
s="${1}"
shift
fi
break
;;
( x-h=* )
h="${1:3}"
;;
( x-h )
shift
h="${1}"
;;
( x-i=* )
i="${1:3}"
if [[ -z "${i}" ]]; then
i=( )
else
i=( -i "${1:3}" )
fi
;;
( x-i )
shift
i=( -i "${1}" )
;;
( x-l=* | x-u=* )
u="${1:3}"
;;
( x-l | x-u )
shift
u="${1}"
;;
( x-m | x--multi )
m=1
;;
( x-p=* )
p="${1:3}"
if [[ -z "${p}" ]]; then
p=( )
else
p=( -p "${1:3}" )
fi
;;
( x-p )
shift
p=( -p "${1}" )
;;
( x-s=* )
s="${1:3}"
;;
( x-s )
shift
s="${1}"
;;
( x-t )
t=( -t )
;;
( x-T )
t=( )
;;
( x-4 )
v=( -4 )
;;
( x-6 )
v=( -6 )
;;
( x-46 | x-64 )
v=( )
;;
( x-* )
echo "Invalid option: '${1}'"
die=1
;;
( * )
echo "Invalid argument: '${1}'"
die=1
;;
esac
shift
done
#----------------------------------------------------------------
# Make sure essential information is present.
#----------------------------------------------------------------
if [[ -z "${u}" ]]; then
echo "User name is missing"
die=1
fi
if [[ -z "${h}" ]]; then
echo "Host name is missing"
die=1
fi
[[ -z "${die}" ]] || exit 1
#----------------------------------------------------------------
# Run screen on the remote only if a session name is given.
#----------------------------------------------------------------
c=( ssh "${v[@]}" "${i[@]}" "${p[@]}" "${t[@]}" "${u}@${h}" )
if [[ -n "${s}" ]]; then
o="-DR"
[[ -n "${m}" ]] && o="-x"
x="exec /usr/bin/env SESSION_NAME='${s}' screen ${o} '${s}'"
c=( "${c[@]}" "${x}" )
fi
exec "${c[@]}"
3.3 操作步骤
-
复制上述代码到一个文件中,例如
ss.sh。 -
执行脚本,根据需要指定选项、会话名、用户名和主机名,如
./ss.sh session1/lisa@centrhub。 -
若指定了会话名,脚本会在远程系统上启动一个
screen会话;若未指定会话名,则以正常方式运行ssh命令。
3.4 注意事项
-
本地系统必须安装OpenSSH包,远程系统必须安装OpenSSH包并运行
sshd守护进程,同时还需安装screen程序,建议在每个系统上配置.screenrc文件。 -
环境变量
SESSION_NAME会在screen命令创建的会话中设置,可供其他脚本使用。
4. 总结
本文介绍了三个实用的Bash脚本,分别用于权威DNS查询、跨Shell会话文件传输以及SSH与Screen的集成。这些脚本能帮助用户更高效地完成系统管理任务,提高工作效率。在使用过程中,需注意各脚本的特点和注意事项,确保操作的安全性和正确性。
通过合理运用这些脚本,用户可以在日常系统管理中节省大量时间和精力,同时避免一些常见的错误和问题。希望这些脚本能为你的工作带来便利。
5. 脚本使用流程对比
| 脚本名称 | 复制代码到文件 | 运行脚本 | 后续操作 | 停止操作 | 注意事项 |
|---|---|---|---|---|---|
| 权威DNS查询脚本 |
复制代码到
dns_lookup.sh
|
根据需要创建副本或链接,传入主机名执行,如
./a example.com
| 无 | 无 | 无 |
| 跨Shell会话文件传输脚本 |
复制代码到
rsend.sh
|
指定选项和文件或目录运行,如
./rsend.sh -p 12345 /path/to/file
| 选择合适命令复制到接收系统执行 |
按
Ctrl - C
停止守护进程
| 无安全机制,注意端口开放 |
| SSH与Screen集成脚本 |
复制代码到
ss.sh
|
指定选项、会话名、用户名和主机名执行,如
./ss.sh session1/lisa@centrhub
| 无 | 无 |
确保系统安装相关程序,配置
.screenrc
文件
|
6. 脚本使用场景分析
6.1 权威DNS查询脚本
- 场景 :当需要进行权威的DNS查询,绕过本地DNS缓存服务器获取准确的DNS记录时使用。
- 优势 :可以根据脚本名称灵活查询不同类型的DNS记录,方便快捷。
6.2 跨Shell会话文件传输脚本
- 场景 :需要在不同系统之间快速传输文件或目录,尤其是需要传输大量文件或包含子目录的情况。
-
优势
:通过
rsync守护进程实现高效传输,且无需在接收系统安装该脚本。
6.3 SSH与Screen集成脚本
-
场景
:在管理多个服务器时,需要频繁建立SSH连接并启动
screen会话,以保持会话的持续性。 - 优势 :通过一个命令完成连接和会话启动,提高操作效率。
7. 脚本执行流程图
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B{选择脚本类型}:::decision
B -->|权威DNS查询脚本| C(复制代码到文件):::process
B -->|跨Shell会话文件传输脚本| D(复制代码到文件):::process
B -->|SSH与Screen集成脚本| E(复制代码到文件):::process
C --> F(创建副本或链接):::process
F --> G(传入主机名执行脚本):::process
D --> H(指定选项和文件或目录运行脚本):::process
H --> I(选择合适命令复制到接收系统执行):::process
I --> J(按`Ctrl - C`停止守护进程):::process
E --> K(指定选项、会话名、用户名和主机名执行脚本):::process
G --> L([结束]):::startend
J --> L
K --> L
8. 进一步优化建议
8.1 权威DNS查询脚本
- 可以添加错误处理机制,当查询失败时给出明确的错误提示。
- 支持批量查询多个主机名,提高查询效率。
8.2 跨Shell会话文件传输脚本
- 增加加密功能,提高传输数据的安全性。
- 实现断点续传功能,避免因网络问题导致传输中断后需要重新开始。
8.3 SSH与Screen集成脚本
-
支持更多的
screen选项,满足不同用户的需求。 - 提供自动重连功能,当SSH连接中断时自动重新连接。
9. 总结与展望
本文详细介绍了三个实用的Bash脚本,包括权威DNS查询脚本、跨Shell会话文件传输脚本以及SSH与Screen集成脚本。通过对脚本的概述、代码展示、操作步骤说明和注意事项提醒,帮助读者了解如何使用这些脚本来提高系统管理的效率。
在实际应用中,读者可以根据具体需求对脚本进行适当的修改和优化,以满足不同的场景。同时,随着技术的不断发展,这些脚本也可以进一步扩展功能,为系统管理工作带来更多的便利。
希望本文能为读者在系统管理方面提供有价值的参考,让大家在日常工作中能够更加轻松地应对各种挑战。未来,我们可以继续探索更多实用的脚本和技术,不断提升系统管理的水平。
超级会员免费看

被折叠的 条评论
为什么被折叠?



