在Linux中,
shift
是一个用于处理命令行参数(位置参数)的Shell内建命令。它的主要作用是移动命令行参数的位置。
shift [n]
n
,默认为 1
。n
表示将命令行参数向左移动的位置数。让我们以一个简单的脚本为例,演示 shift
的用法:
#!/bin/bash
echo "Before shift: \$1=$1, \$2=$2, \$3=$3"
# 使用 shift 移动两个位置
shift 2
echo "After shift: \$1=$1, \$2=$2, \$3=$3"
如果你运行这个脚本并提供三个参数:
./example.sh one two three
输出将是:
Before shift: $1=one, $2=two, $3=three
After shift: $1=three, $2=, $3=
在这个例子中,shift 2
将命令行参数向左移动了两个位置,因此 $1
变成了原来的 $3
,而 $2
和 $3
变成了空白。
shift
在脚本中通常用于处理可变数量的命令行参数。通过反复使用 shift
,你可以逐步处理所有的命令行参数。
如果 shift
移动的位置数大于当前剩余的命令行参数数,剩余的参数会变成空。
shift
不会改变 $0
(脚本名称)和 $#
(命令行参数的总数)。
shift
在循环中使用时,可以用来处理可变数量的参数。例如,一个脚本需要处理不同数量的参数,可以使用循环结构和 shift
动态地处理这些参数。
while [ "$#" -gt 0 ]; do
case "$1" in
-a)
# 处理参数 -a
shift
;;
-b)
# 处理参数 -b
shift
;;
*)
# 处理其他参数
shift
;;
esac
done
这样,shift
可以在循环中帮助我们逐步处理不同的命令行参数。
[root@gh-shell 1-27] vim run.sh
[root@gh-shell 1-27] cat run.sh
#!/bin/bash
while(( $# !=0 ))
do
echo "第一个参数为 $1,参数的个数是 $# ,所有的位置变量内容是 $@"
#删除第一个位置变量,将所有的位置变量左移
shift
done
[root@gh-shell 1-27]# bash run.sh gaohui gaofei huya junxue tangrong changai
第一个参数为 gaohui,参数的个数是 6 ,所有的位置变量内容是 gaohui gaofei huya junxue tangrong changai
第一个参数为 gaofei,参数的个数是 5 ,所有的位置变量内容是 gaofei huya junxue tangrong changai
第一个参数为 huya,参数的个数是 4 ,所有的位置变量内容是 huya junxue tangrong changai
第一个参数为 junxue,参数的个数是 3 ,所有的位置变量内容是 junxue tangrong changai
第一个参数为 tangrong,参数的个数是 2 ,所有的位置变量内容是 tangrong changai
第一个参数为 changai,参数的个数是 1 ,所有的位置变量内容是 changai
[root@gh-shell 1-27]#
执行了两遍,取了两次值
[root@gh-shell 1-27] a=b
[root@gh-shell 1-27] b=10
[root@gh-shell 1-27] echo $a
b
[root@gh-shell 1-27] python3
Python 3.6.8 (default, Nov 14 2023, 16:29:52)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a=10
>>> b=a
>>> b
10
>>>
>>> exit()
总体来说,这个例子展示了在Shell和Python中如何创建变量、赋值以及查看变量的值。在Python中,变量的类型可以动态变化,而在Shell中,变量的类型通常由赋值的内容决定。
[root@gh-shell 1-27] echo ${!a}
10
[root@gh-shell 1-27]#
!a表示 先取b的值
再把$b取值 相当于取了两次值---->间接引用
想到eval命令—>让bash解释2次,这样可以执行2次命令
[root@gh-shell 1-27] a='cat cc.txt'
[root@gh-shell 1-27] vim cc.txt
[root@gh-shell 1-27] cat cc.txt
sanchuang
[root@gh-shell 1-27] echo $a
cat cc.txt
[root@gh-shell 1-27] eval $a
sanchuang
[root@gh-shell 1-27]#
bash自带的处理字符串
echo ${#a} $a中字符串的个数
echo ${a:3} $a中从第三个开始取直到结束
echo ${a:3:2}$a中从第三个开始去两个字符
echo ${a: -1}取最后一个字符
echo ${a:-} 如果a变量不存在就输出空值
echo ${a:-"sanchuang"} 如果a变量不存在就输出sanchuang,如果a变量有值就输出a的值
[root@web1 init.d]# a=123
[root@web1 init.d]# b=${a:-"sanchuang"}
[root@web1 init.d]# echo $b
123
[root@web1 init.d]#
[root@web1 init.d]# a=
[root@web1 init.d]# b=${a:-"sanchuang"}
[root@web1 init.d]# echo $b
sanchuang
[root@web1 init.d]#
echo ${a#*.} 从左边开始删除直到遇到.为止
echo ${a##*.} 从左边开始删除直到遇到最后一个.为止
echo ${a%.*}从右面开始删除直到遇到.为止
echo ${a%%.*}从右面开始删除直到遇到最后一个.为止
echo ${a/abc/111} 将变量a中的第一个abc替换成111
echo ${a//abc/xyz}将变量a中的所有的abc替换成xyz
cd /etc/init.d/ '里边有一个network脚本'
. /etc/init.d/functions '执行 /etc/init.d/functions 这个脚本 在当前shell中执行'
if [ ! -f /etc/sysconfig/network ]; then '-f是判断文件存不存在,如果/etc/sysconfig/network 不存在 就退出脚本返回6'
exit 6
fi
. /etc/sysconfig/network '执行 /etc/sysconfig/network 脚本'
if [ -f /etc/sysconfig/pcmcia ]; then '如果/etc/sysconfig/pcmcia 存在 就执行. /etc/sysconfig/pcmcia'
. /etc/sysconfig/pcmcia
fi
# Check that networking is up. '检查网络是否正常'
[ "${NETWORKING}" = "no" ] && exit 6 '判断NETWORKING这个变量是否等于no,并且返回值是否为6'
# if the ip configuration utility isn't around we can't function. '如果没有IP配置工具,我们就无法正常工作。'
[ -x /sbin/ip ] || exit 1 '判断/sbin/ip是否可以执行 或者 返回值是否为1'
CWD=$(pwd) '这个命令用于获取当前工作目录(Current Working Directory)并将其保存在变量 CWD 中。'
cd /etc/sysconfig/network-scripts '进入/etc/sysconfig/network-scripts 这个目录'
. ./network-functions '执行当前目录下的network-functions脚本'
# find all the interfaces besides loopback. '查找除loopback以外的所有接口。'
# ignore aliases, alternative configurations, and editor backup files '忽略别名、可选配置和编辑器备份文件'
interfaces=$(ls ifcfg-* | \
LC_ALL=C sed -e "$__sed_discard_ignored_files" \
-e '/\(ifcfg-lo$\|:\|ifcfg-.*-range\)/d' \
-e '{ s/^ifcfg-//g;s/[0-9]/ &/}' | \
LC_ALL=C sort -k 1,1 -k 2n | \
LC_ALL=C sed 's/ //')
rc=0
解释一下:interfaces
每一行后边的\是单纯的续航
ls ifcfg-*
查找当前文件夹下ifcfg-开头的文件
LC_ALL=C
: 这是设置环境变量LC_ALL
的部分。LC_ALL
是用来设置所有语言环境的环境变量。在这里,通过将其设置为C
,强制使用默认的 “C” 或 “POSIX” 语言环境。这通常用于确保在不同的系统上得到一致的结果,以避免与本地化相关的问题。sed -e "$__sed_discard_ignored_files" -e '/\(ifcfg-lo$\|:\|ifcfg-.*-range\)/d' -e '{ s/^ifcfg-//g;s/[0-9]/ &/}' -e "$__sed_discard_ignored_files": 其实就是传进来一个变量 这部分使用 -e 选项指定了 sed 的一个编辑脚本。 $__sed_discard_ignored_files 是一个变量,其中包含了一些 sed 模式匹配规则,用于指定要排除(丢弃)的文件名模式。 例如,如果 $__sed_discard_ignored_files 的内容是 "/pattern1/d;/pattern2/d;...",那么这部分的作用是根据定义的模式规则丢弃匹配的行(文件名)。 -e '/\(ifcfg-lo$\|:\|ifcfg-.*-range\)/d': 这是另一个 -e 选项,指定了另一个 sed 的编辑脚本。 /\(ifcfg-lo$\|:\|ifcfg-.*-range\)/d 是一个模式,它使用正则表达式匹配文件名。具体: \(ifcfg-lo$\|:\|ifcfg-.*-range\):这是一个正则表达式组,它匹配三种模式之一: ifcfg-lo$:匹配以 "ifcfg-lo" 结尾的文件名。 ::匹配包含 ":" 的文件名。 ifcfg-.*-range:匹配以 "ifcfg-" 开头,以 "-range" 结尾的文件名。 /d:这是 sed 的删除命令,它删除与模式匹配的行(文件名)。 -e '{ s/^ifcfg-//g;s/[0-9]/ &/}': 这是第三个 -e 选项,指定了另一个 sed 的编辑脚本。 这部分主要包含两个 sed 替换命令: s/^ifcfg-//g:将行中开头的 "ifcfg-" 替换为空字符串,即删除 "ifcfg-" 前缀。 s/[0-9]/ &/:将行中的每个数字前插入一个空格,即在数字前添加一个空格。
LC_ALL=C sort -k 1,1 -k 2n
sort
:
sort
命令用于对文本进行排序。-k 1,1 -k 2n
:
-k 1,1
:表示按照第一个字段进行排序。这里1,1
意味着只使用第一个字段进行排序。-k 2n
:表示按照第二个字段进行数值排序。这里2n
意味着使用第二个字段,并将其解释为数字进行排序。综合起来,
LC_ALL=C sort -k 1,1 -k 2n
的作用是使用sort
对文本进行排序:
- 首先按照第一个字段进行字母顺序排序。
- 如果两行的第一个字段相同,则按照第二个字段进行数值顺序排序。
sed 's/ //'
: 这是一个sed
替换命令,其模式为s/ //
,表示将每一行中的第一个空格替换为空字符串。
# See how we were called. '看看我们是怎么被称呼的'
case "$1" in 'case选项通过位置变量1'
start) '如果输入的是start'
[ "$EUID" != "0" ] && exit 4 '如果变量EUID不等于0并且返回值为4'
rc=0 'rc是return code 等于0'
# IPv6 hook (pre IPv4 start) ''
if [ -x /etc/sysconfig/network-scripts/init.ipv6-global ]; then '如果这个文件有可执行权限init.ipv6-global'
/etc/sysconfig/network-scripts/init.ipv6-global start pre 'start和pre是两个参数 相当于$1和$2'
fi
apply_sysctl 'apply_sysctl 可能是一个用于应用系统参数(sysctl)的函数或脚本。'
#tell NM to reload its configuration '告诉NM重新加载它的配置'
if [ "$(LANG=C nmcli -t --fields running general status 2>/dev/null)" = "running" ]; then
nmcli connection reload '重新加载网络连接配置'
fi
# bring up loopback interface '启动环回接口'
action $"Bringing up loopback interface: " ./ifup ifcfg-lo
case "$VLAN" in '如果$VLAN的值为yes'
yes)
if [ ! -d /proc/net/vlan ] && ! modprobe 8021q >/dev/null 2>&1 ; then
net_log $"No 802.1Q VLAN support available in kernel."
fi
;;
esac
vlaninterfaces=""
interfaces=""
xdslinterfaces=""
bridgeinterfaces=""
“$(LANG=C nmcli -t --fields running general status 2>/dev/null)” = “running”
这是一个 Bash Shell 中的条件表达式,用于判断 NetworkManager 服务是否正在运行。让我解释这个表达式的不同部分:
LANG=C
:
- 这是一个环境变量设置,将语言环境设置为 “C” 或 “POSIX”。
- 在这里使用的目的是确保
nmcli
命令输出的文本是在一个固定的、不受本地化影响的语言环境下产生的。这是为了避免在不同系统环境下输出格式发生变化。
nmcli -t --fields running general status
:
- 这是一个
nmcli
命令,用于获取 NetworkManager 的运行状态。-t
选项表示使用制表符分隔的输出格式。--fields running
表示仅显示 “running” 字段的值。general status
是nmcli
命令的参数,指定要获取的信息类型。
2>/dev/null
:
- 这是一个重定向操作符,将标准错误(stderr)输出重定向到
/dev/null
,以忽略任何错误消息。这样做是为了避免在检查 NetworkManager 运行状态时输出错误消息到标准错误。
"$(...) = "running"
:
$()
是命令替换语法,用于执行括号中的命令,并将其输出作为字符串返回。"$(LANG=C nmcli -t --fields running general status 2>/dev/null)"
表示执行nmcli
命令,获取 NetworkManager 运行状态,并将其作为字符串进行比较。=
是字符串比较运算符,判断命令输出的字符串是否等于 “running”。综合起来,整个表达式的作用是判断 NetworkManager 服务是否正在运行。如果运行状态为 “running”,则整个条件表达式为真。这通常用于在脚本中进行条件性的操作,例如重新加载配置或执行其他操作,以确保 NetworkManager 处于正常运行状态。
action $"Bringing up loopback interface: " ./ifup ifcfg-lo
action $"Bringing up loopback interface: "
:
- 这一部分通常是调用系统的 init 脚本中的
action
函数,用于在控制台上显示一个带有动作标签的消息。$"Bringing up loopback interface: "
是一个用于国际化的字符串,$
是用于本地化的标记,"Bringing up loopback interface: "
是带有动作标签的消息。./ifup ifcfg-lo
:
- 这是一个相对路径的命令,调用
ifup
程序并传递了一个参数ifcfg-lo
。ifup
通常是一个用于启动网络接口的工具,而ifcfg-lo
可能是一个配置文件,指定了 loopback 接口的相关配置信息。综合起来,整个命令的意义可能是:
- 使用
action
函数显示带有动作标签的消息,该消息是 "Bringing up loopback interface: "。- 调用
ifup
工具,以启动 loopback 接口,并且可能通过ifcfg-lo
参数指定了相关的配置文件。
case "$VLAN" in '如果$VLAN的值为yes' yes) if [ ! -d /proc/net/vlan ] && ! modprobe 8021q >/dev/null 2>&1 ; then net_log $"No 802.1Q VLAN support available in kernel." fi ;; esac vlaninterfaces="" interfaces="" xdslinterfaces="" bridgeinterfaces=""
if [ ! -d /proc/net/vlan ] && ! modprobe 8021q >/dev/null 2>&1 ; then
:
这是在
$VLAN
的值为 “yes” 时执行的代码块。 if语句用于检查以下两个条件:
! -d /proc/net/vlan
:检查/proc/net/vlan
目录是否不存在。! modprobe 8021q >/dev/null 2>&1
:尝试加载内核模块8021q
,并检查是否成功。>/dev/null 2>&1
用于将输出和错误重定向到/dev/null
,即忽略输出和错误。如果任一条件为真(即目录不存在或加载模块失败),则执行
net_log $"No 802.1Q VLAN support available in kernel."
。
net_log
函数可能用于记录一些网络相关的消息。vlaninterfaces, interfaces, xdslinterfaces,bridgeinterfaces 定义这四个变量为空。
综合起来,整个代码片段的作用可能是:
- 如果
$VLAN
的值是 “yes”,则检查是否存在 VLAN 支持的必要条件(特定目录和加载模块),并在条件不满足时记录相关消息。- 无论
$VLAN
的值是什么,都将一些变量赋值为空字符串。这可能是为了确保这些变量在后续的脚本中处于已定义的状态,即使在不需要 VLAN 的情况下也是如此。
# bring up all other interfaces configured to come up at boot time '调出配置为在引导时启动的所有其他接口'
for i in $interfaces; do 'for循环变量i去取interfaces的值'
unset DEVICE TYPE SLAVE NM_CONTROLLED '取消变量的值'
eval $(LANG=C grep -F "DEVICE=" ifcfg-$i) '执行$()最后生成的命令 -F是固定的字符串/正则,用于从 ifcfg-$i 文件中读取网络接口的配置信息,并将其设置为对应的变量。下同'
eval $(LANG=C grep -F "TYPE=" ifcfg-$i)
eval $(LANG=C grep -F "SLAVE=" ifcfg-$i)
eval $(LANG=C grep -F "NM_CONTROLLED=" ifcfg-$i)
if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi
if [ "$SLAVE" = "yes" ] && ( ! is_nm_running || is_false $NM_CONTROLLED ) ; then
continue
fi
if [ "${DEVICE##cipcb}" != "$DEVICE" ] ; then
interfaces="$interfaces $i"
continue
fi
if [ "$TYPE" = "xDSL" -o "$TYPE" = "Modem" ]; then
xdslinterfaces="$xdslinterfaces $i"
continue
fi
if [ "$TYPE" = "Bridge" ]; then
bridgeinterfaces="$bridgeinterfaces $i"
continue
fi
if [ "$TYPE" = "IPSEC" ] || [ "$TYPE" = "IPIP" ] || [ "$TYPE" = "GRE" ]; then
interfaces="$interfaces $i"
continue
fi
if [ "${DEVICE%%.*}" != "$DEVICE" -o "${DEVICE##vlan}" != "$DEVICE" ] ; then
vlaninterfaces="$vlaninterfaces $i"
continue
fi
if LANG=C grep -EL "^ONBOOT=['\"]?[Nn][Oo]['\"]?" ifcfg-$i > /dev/null ; then
# this loads the module, to preserve ordering
is_available $i
continue
fi
action $"Bringing up interface $i: " ./ifup $i boot
[ $? -ne 0 ] && rc=1
done
条件判断和处理不同类型的网络接口:
- 如果
SLAVE
为 “yes” 且 NetworkManager 没有运行或者NM_CONTROLLED
为假,则跳过当前循环。- 如果接口的名称以 “cipcb” 开头,将其添加到
interfaces
中。- 如果接口的类型为 “xDSL” 或 “Modem”,将其添加到
xdslinterfaces
中。- 如果接口的类型为 “Bridge”,将其添加到
bridgeinterfaces
中。- 如果接口的类型为 “IPSEC”、“IPIP” 或 “GRE”,将其添加到
interfaces
中。- 如果接口的名称包含 “.” 或以 “vlan” 开头,将其添加到
vlaninterfaces
中。- 如果配置文件中指定接口在启动时不启用(
ONBOOT
为 “NO”),则加载相应的模块。
action $"Bringing up interface $i: " ./ifup $i boot
:
- 在最后的条件判断后,如果没有满足上述特殊类型的接口,将接口启动,并通过
action
函数显示带有动作标签的消息。./ifup $i boot
是执行启动接口的命令。[ $? -ne 0 ] && rc=1
:
- 如果上述启动接口的命令返回值不为 0,将
rc
变量设置为 1,表示有错误发生。
# Bring up xDSL and VPN interfaces
for i in $vlaninterfaces $bridgeinterfaces $xdslinterfaces $interfaces ; do
if ! LANG=C grep -EL "^ONBOOT=['\"]?[Nn][Oo]['\"]?" ifcfg-$i >/dev/null 2>&1 ; then
action $"Bringing up interface $i: " ./ifup $i boot
[ $? -ne 0 ] && rc=1
fi
done
# Add non interface-specific static-routes.
if [ -f /etc/sysconfig/static-routes ]; then
if [ -x /sbin/route ]; then
grep "^any" /etc/sysconfig/static-routes | while read ignore args ; do
/sbin/route add -$args
done
else
net_log $"Legacy static-route support not available: /sbin/route not found"
fi
fi
通过
for
循环迭代处理不同类型的网络接口,包括VLAN、桥接、xDSL和VPN。使用
grep
命令检查对应接口的配置文件(ifcfg-$i
)中是否设置了ONBOOT
参数为"NO"。LANG=C
设置环境语言为英文,确保在检查文件时不受语言环境的影响。如果未找到包含"ONBOOT=‘NO’"的行,则执行
./ifup $i boot
命令以启动该接口。action
命令用于记录日志。如果接口启动不成功(
[ $? -ne 0 ]
),将rc
变量设置为1,表示发生错误。检查是否存在静态路由配置文件
/etc/sysconfig/static-routes
。如果文件存在,并且
/sbin/route
(route命令)可执行,使用grep
命令找到以"any"开头的行。对于每一行,使用
/sbin/route add
命令添加静态路由,参数为从配置文件中读取的args
。如果
/sbin/route
不可执行,记录一条消息指示"Legacy static-route support not available: /sbin/route not found"。
# IPv6 hook (post IPv4 start)
if [ -x /etc/sysconfig/network-scripts/init.ipv6-global ]; then '如果这个文件有可执行权限'
/etc/sysconfig/network-scripts/init.ipv6-global start post '执行这个脚本,并且传递参数start post'
fi
# Run this again to catch any interface-specific actions
apply_sysctl '运行这个函数'
touch /var/lock/subsys/network '创建空文件'
[ -n "${NETWORKDELAY}" ] && /bin/sleep ${NETWORKDELAY} '判断字符串${NETWORKDELAY}是否为空,如果环境变量 NETWORKDELAY 非空,那么执行 sleep 命令'
;;
stop)
[ "$EUID" != "0" ] && exit 4 '如果EUID不为0,就返回4'
# Don't shut the network down if root or /usr is on NFS or a network
# block device.
root_fstype=$(gawk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/" && $3 != "rootfs") { print $3; }}' /proc/mounts)
usr_fstype=$(gawk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/usr" && $3 != "rootfs") { print $3; }}' /proc/mounts)
'获取根目录和 /usr 目录当前所使用的文件系统类型。'
if [[ "${root_fstype}" == nfs* || "${usr_fstype}" == nfs* ]] || systemctl show --property=RequiredBy -- -.mount usr.mount | grep -q 'remote-fs.target' ; then
net_log $"rootfs or /usr is on network filesystem, leaving network up"
exit 1
fi
unset root_fstype usr_fstype
if [[ "${root_fstype}" == nfs* || "${usr_fstype}" == nfs* ]] || systemctl show --property=RequiredBy -- -.mount usr.mount | grep -q 'remote-fs.target' ; then net_log $"rootfs or /usr is on network filesystem, leaving network up" exit 1 fi
检测这个两个变量root_fstype,usr_fstype是否以nfs开头或者通过
systemctl show
命令检查.mount
和usr.mount
单元之间的依赖关系,并使用grep
命令检查是否存在remote-fs.target
。
- 如果条件成立,即根文件系统或
/usr
文件系统是网络文件系统,或者存在与remote-fs.target
相关的 systemd 单元依赖,那么记录一条消息表示 “rootfs or /usr is on network filesystem, leaving network up”。- 然后,通过
exit 1
终止脚本并返回退出码 1,这通常表示脚本运行失败或中止。- 最后,通过
unset
命令清除变量root_fstype
和usr_fstype
。
# Don't shut the network down when shutting down the system if configured
# as such in sysconfig
if is_false "$IFDOWN_ON_SHUTDOWN"; then '如果这个变量是假的'
if systemctl is-system-running | grep -q 'stopping'; then '使用 systemctl is-system-running 命令检查系统当前的运行状态。如果系统正在关机过程中(状态包含 'stopping'),则执行以下操作:'
net_log $"system is shutting down, leaving interfaces up as requested" info '记录一条信息日志,表示系统正在关机,而网络接口将被保持启动状态。'
exit 0 '使用 exit 0 终止脚本并返回退出码 0,表示成功执行。'
fi
fi
vlaninterfaces=""
interfaces=""
xdslinterfaces=""
bridgeinterfaces=""
remaining=""
rc=0
'重置一些变量,return code 设置为0'
# get list of bonding, , and xdsl interfaces
for i in $interfaces; do
unset DEVICE TYPE '删除这两个变量'
eval $(LANG=C grep -F "DEVICE=" ifcfg-$i) '执行DEVICE=的值'
eval $(LANG=C grep -F "TYPE=" ifcfg-$i) '执行TYPE=的值'
'使用 grep 命令从接口配置文件 ifcfg-$i 中提取 DEVICE 和 TYPE 的值,并使用 eval 命令将它们赋值给相应的变量。'
if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi '如果这个字符串为空,设置DEVICE=$i'
if [ "${DEVICE##cipcb}" != "$DEVICE" ] ; then
interfaces="$interfaces $i"
continue
fi
if [ "$TYPE" = "IPSEC" ] || [ "$TYPE" = "IPIP" ] || [ "$TYPE" = "GRE" ]; then
interfaces="$interfaces $i"
continue
fi
'如果接口名以 "cipcb" 开头,则将其添加到 VPN 接口列表中。如果接口的类型为 "IPSEC"、"IPIP" 或 "GRE",同样将其添加到 VPN 接口列表中。'
if [ "$TYPE" = "Bridge" ]; then
bridgeinterfaces="$bridgeinterfaces $i"
continue
fi
'如果接口的类型为 "Bridge",则将其添加到桥接接口列表中。'
if [ "$TYPE" = "xDSL" -o "$TYPE" = "Modem" ]; then
xdslinterfaces="$xdslinterfaces $i"
continue
fi
'如果接口的类型为 "xDSL" 或 "Modem",则将其添加到 xDSL 接口列表中。'
if [ "${DEVICE%%.*}" != "$DEVICE" -o "${DEVICE##vlan}" != "$DEVICE" ] ; then
vlaninterfaces="$vlaninterfaces $i"
continue
fi
'如果 DEVICE 的第一个点之前的部分不等于整个 DEVICE,或者 DEVICE 以 "vlan" 开头,那么将其添加到 VLAN 接口列表中'
remaining="$remaining $i"
'如果接口不属于以上任何一类,则将其添加到 remaining 列表中。'
done
for i in $interfaces $xdslinterfaces $bridgeinterfaces $vlaninterfaces $remaining; do
'使用 for 循环遍历 VPN 接口、xDSL 接口、桥接接口、VLAN 接口以及剩余接口的列表。'
unset DEVICE TYPE '在每次循环迭代开始时,使用 unset 命令重置 DEVICE 和 TYPE 变量。'
(. ./ifcfg-$i '在子shell中执行 . 命令,从而在当前环境中加载接口配置文件 ifcfg-$i。'
if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi '如果在配置文件中未找到 DEVICE,则将其设置为当前接口名。'
if ! check_device_down $DEVICE; then '使用 check_device_down 函数检查接口是否已关闭。'
action $"Shutting down interface $i: " ./ifdown $i boot '如果接口未关闭,使用 ./ifdown $i boot 命令关闭接口,并记录操作。'
[ $? -ne 0 ] && rc=1 '如果关闭接口的命令执行失败([ $? -ne 0 ]),将 rc 变量设置为 1,表示发生错误。'
fi
)
done
action $"Shutting down loopback interface: " ./ifdown ifcfg-lo '使用 ./ifdown ifcfg-lo 命令关闭回环接口,并记录操作。'
sysctl -w net.ipv4.ip_forward=0 > /dev/null 2>&1 '使用 sysctl 命令将 IPv4 的 IP 转发设置为 0,表示禁用。通过 > /dev/null 2>&1 将输出重定向到空设备,以避免输出到终端。'
# IPv6 hook (post IPv4 stop)
if [ -x /etc/sysconfig/network-scripts/init.ipv6-global ]; then '如果这个文件有可执行权限'
/etc/sysconfig/network-scripts/init.ipv6-global stop post '执行这边脚本,并传递两个参数'
fi
rm -f /var/lock/subsys/network '删除这个文件'
;;
status)
echo $"Configured devices:"
echo lo $interfaces
'打印已配置的设备列表,包括回环接口 lo 和其他接口 $interfaces。'
echo $"Currently active devices:"
echo $(/sbin/ip -o link show up | awk -F ": " '{ print $2 }')
'打印当前活动的设备列表,使用 /sbin/ip -o link show up 命令获取已启动的网络接口,然后使用 awk 命令提取接口名。'
;;
restart|force-reload) '如果脚本的参数是 restart 或 force-reload'
cd "$CWD" '切换到脚本所在的目录'
$0 stop '使用 $0 stop 命令停止网络服务'
$0 start '使用 $0 start 命令启动网络服务'
rc=$? '将结果保存在rc中'
;;
*)
echo $"Usage: $0 {start|stop|status|restart|force-reload}"
exit 2
'上如果脚本的参数不是上述提到的情况之一,则打印使用说明并以退出码 2 退出脚本。'
esac
exit $rc
规定一个时间去做某事
有个crond程序:到点帮助我们去执行脚本
任务:做的事情
计划:到时到点
相当于闹铃
:生活里的计划任务
crond程序:一直在内存里运行,会每间隔1分钟去查看所有用户的计划任务,然后去帮助执行
[root@gh-shell 1-28] ps aux|grep crond '看进程'
root 741 0.0 0.0 126416 1720 ? Ss 1月16 0:00 /usr/sbin/crond -n
root 104304 0.0 0.0 112824 976 pts/1 S+ 08:42 0:00 grep --color=auto crond
[root@gh-shell 1-28] service crond stop '停止crond服务'
Redirecting to /bin/systemctl stop crond.service
[root@gh-shell 1-28] ps aux|grep crond
root 104334 0.0 0.0 112824 976 pts/1 S+ 08:43 0:00 grep --color=auto crond
[root@gh-shell 1-28] service crond start '开启crond服务'
Redirecting to /bin/systemctl start crond.service
[root@gh-shell 1-28] ps aux|grep crond
root 104354 21.0 0.0 126388 1684 ? Ss 08:43 0:00 /usr/sbin/crond -n
root 104357 0.0 0.0 112824 972 pts/1 S+ 08:43 0:00 grep --color=auto crond
[root@gh-shell 1-28]#
crond系统定时任务
crontab
-e: 编辑crontab定时任务
-l: 查询crontab任务
-r: 删除当前用户所有的crontab任务
第一个“*” 一小时当中的第几分钟 0-59
第二个“*” 一天当中的第几小时 0-23
第三个“*” 一个月当中的第几天 1-31
第四个“*” 一年当中的第几月 1-12
第五个“*” 一周当中的星期几 0-7(0和7都代表星期日)
* 代表任何时间。比如第一个“”就代表一小时中每分钟都执行一次的意思。
, 代表不连续的时间。比如“0 8,12,16 * * * 命令”,就代表在每天的8点0分,12点0分,16点0分都执行一次命令
- 代表连续的时间范围。比如“0 5 * * 1-6命令”,代表在周一到周六的凌晨5点0分执行命令
*/n 代表每隔多久执行一次。比如“/10 * * * * 命令”,代表每隔10分钟就执行一遍命令
'编写一个脚本backup 1og.sh实现备份/var/1og目录下的所有文件到/scbackup目录下,要求文件名是包含当天日期精确到秒,文件名例如:20220412208401-1og.tar.gz。同时要求删除七天前的备份文件,只保留最近7天的文件。'
'执行backup_log.sh 每天的晚上2:30执行----->利用计划任务去执行'
[root@gh-shell 1-28] vim backup_log.sh
#!/bin/bash
#获得当前的日期
ctime=$(date "+%Y%m%d%H%M%S")
#备份/var/log目录到/scbackup
mkdir -p /scbackup
tar -czf /scbackup/${ctime}-log.tar.gz /var/log
if (( $? ==0 ));then
echo "${ctime} backup ok!" >>/var/log/backup_log.log
else
echo "${ctime} backup failed!" >>/var/log/backup_log.log
fi
#删除七天前的备份文件
find /scbackup -mtime +7 -type f -name "*log.tar.gz" -exec rm -rf {} \;
[root@gh-shell 1-28]#
'执行backup_log.sh 每天的晚上2:30执行----->利用计划任务去执行'
[root@gh-shell 1-28] crontab -e
30 2 * * * bash /shell/1-28/backup_log.sh
no crontab for root - using an empty one
crontab: installing new crontab
[root@gh-shell 1-28] crontab -l
30 2 * * * bash /shell/1-28/backup_log.sh
[root@gh-shell 1-28]#
[root@gh-shell 1-28] cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
[root@gh-shell 1-28]#
20 2 3 2 * bash a.sh 2月3日的2点20分去执行
20 2 * * * bash a.sh 每天的2点20去执行
20 2 * * 1-5 bash a.sh 周1到周5去执行
*/5 * * * * bash a.sh 每隔5分钟执行一次
0 */5 * * * bash a.sh 没间隔5小时执行一次
20 2 * * 1,3,5 bash a.sh 每周的周1,周3,周5的2点20去执行
/ 间隔
- 连续
, 不连续的
(个人用户)新增的计划任务放在了: /var/spool/cron/ 这个目录下边,一个用户对应一个文件
[root@gh-shell 1-28] cd /var/spool/cron/ [root@gh-shell cron] ls root [root@gh-shell cron] cat root 30 2 * * * bash /shell/1-28/backup_log.sh [root@gh-shell cron]#
(操作系统)会放在 /etc/cron下边
1.
看日志!
:/var/log/cron[root@gh-shell cron] cd /var/log/ [root@gh-shell log] cat cron Jan 18 09:26:01 gh-shell run-parts(/etc/cron.daily)[106457]: finished man-db.cron Jan 18 09:26:01 gh-shell anacron[105228]: Job `cron.daily' terminated (produced output) [root@gh-shell log]#
2.
看效果!
去/var/spool/cron/下边看,是谁创建的计划任务
操作系统要完成的计划任务
写计划任务执行的时间,定时去执行 /shell/sc.sh
1.12月3日5:50执行 脚本
50 5 3 12 * bash /shell/sc.sh
2.每间隔18分钟执行
*/18 * * * * bash /shell/sc.sh
3.每间隔2小时执行
0 */2 * * * * bash /shell/sc.sh
4.每周的1,3,5的5点30执行
30 5 * * * 1,3,5 bash /shell/sc.sh
5.每天的6点,8点,11点执行
0 6,8,11 * * * bash /shell/sc.sh
6.12月5号到28号的每天8点30执行
30 8 5-28 12 * bash /shell/sc.sh
date
是 Linux 中用于显示或设置系统日期和时间的命令。以下是 date
命令的一些详细用法:
显示当前日期和时间:
date
Fri Jan 28 09:30:00 UTC 2024
显示特定格式的日期和时间:
date "+%Y-%m-%d %H:%M:%S"
2024-01-28 09:30:00
+%Y-%m-%d %H:%M:%S
是指定的日期时间格式,可以根据需要进行修改。设置系统日期和时间:
sudo date MMDDhhmm[[CC]YY][.ss]
sudo date 012809302024.00
从文件中读取日期和时间:
date -s "$(cat /path/to/file)"
date
命令。计算未来或过去的日期:
date -d "2 days ago"
Wed Jan 26 09:30:00 UTC 2024
-d
选项用于指定相对日期。其他可能的值包括 2 days ago
、next Monday
等。显示纪元时间戳:
date +%s
显示本地时区的日期和时间:
date +"%Y-%m-%d %H:%M:%S %Z"
2024-01-28 09:30:00 UTC
%Z
表示显示时区信息。显示 UTC 时间:
date -u
这只是 date
命令的一些基本用法,还有其他选项和格式可以根据具体需求进行使用。你可以使用 man date
命令来查看 date
的手册页,以获取更多详细信息。
显示格式为20220412208401
date "+%Y%m%d%H%M%S"
更改系统时间
date -s "2024-2-11"
压缩:tar -zcvf XXX.tar.gz XXX
解压:tar -zxvf XXX.tar.gz -C 解压目的地
[root@server lianxi] tar -zcvf 课外作业.docx.tar.gz 课外作业.docx //压缩文件
课外作业.docx
[root@server lianxi] ls
课外作业.docx 课外作业.docx.tar.gz 上机作业.doc
[root@server lianxi] tar -zxvf 课外作业.docx.tar.gz -C /test //解压到指定文件夹
[root@server lianxi] ls /test
192.168.209.145 192.168.209.146 backup.sh create_file.sh which.sh 课外作业.docx
文件打包
tar
文件压缩的好处:
方便文件在网上的传输,节约存储空间.文件打包:方便移动
tar 文件打包
tar -cf 打包文件
tar -tvf 列出所有文件
tar -xf 解包文件tar -cvf xxx.tar /boot/ 将boot目录打包、
c create 创建
f filename 文件名称
v 显示执行过程的详细信息file 文件名 查看一个文件的类型
file a.txt一次打包两个目录
tar -cvf xx.tar /boot/ /etc/test/查看包中的内容
tar -tvf xxx.tar将包解压到指定的目录中
tar -xvf xxx.tar -C /tmp/查看一个目录的大小
du -sh /boot/
查看一个文件的大小
ll -h xxx.tartar 中的参数
-z gzip 工具压缩 压缩后缀是.gz解压缩包
tar -zxvf xxx.tar.gz -C /tmp/bzip2 压缩工具,后缀是.tar.bz2
压缩:tar cjvf xxx.tar.bz2
-j 表示使用的是bzip2压缩工具
解压:tar xjvf xxx.tar.bz2 -C /tmp/bzip2压缩的文件比 gzip压缩的文件小
zip 压缩工具:zip -r xxx.zip /etc/passwd
解压缩zip unzip xxx.zip -d /tmp/gzip 压缩工具:压缩后原文件会消失
gzip 1.txt 压缩后的文件是 1.txt.gz
gzip 解压缩:
gzip -d 1.txt.gz
作用:查找文件目录
参数:``-name 按名称查找;
-user 按用户查找;
-group 按组查找;
-empty 查找空目录空文件;
-perm 按权限查找;
-mtime 按修改时间查找;
-size 按容量大小查找;
-exec 对找到的内容执行命令;
-type` 按类型查找,f-文件 d-目录 b c-设备 l-链接;-o 或者条件;-a 并且条件。
示例:
[root@centos7 ~]# find -name test.txt #查找名称为test.py的文件
[root@centos7 ~]# find -iname tesT.txt #查找test.py文件,不区分大小写
[root@centos7 ~]# find / -user game #查找用户名为game的文件或目录
[root@centos7 ~]# find ./ -group game #查找组名为game的文件或目录
[root@centos7 ~]# find ./ empty #查找空的目录或文件
[root@centos7 ~]# find ./ -perm 644 #查找当前目录下权限为644的文件
[root@centos7 ~]# find /home -mtime -3 #查找home下所有3天内修改过的文件或目录
[root@centos7 ~]# find /home -mtime +5 #查找home下所有5天前被修改过的文件或目录
[root@centos7 ~]# find /home -mtime 6 #查找6天前当天修改的文件或目录
[root@centos7 ~]# find /data -size +20M #查找data目录下大于20M的文件或目录
[root@centos7 ~]# find /home -size +2M -exec ls -l {} ; #列出home下大于2M的文件或目录
[root@centos7 ~]# find /home -size +3M -a -type f -exec rm -rf {} ; #删除home下大于3M的文件
[root@centos7 ~]# find /home -type f -name “*.log” #查找日志文件
[root@centos7 ~]# find /home -amin n #最后n分钟
[root@centos7 ~]# find /home -atime n #最后n天
[root@centos7 ~]# find /home -cmin n #最后n分钟改变状态
[root@centos7 ~]# find /home -ctime n #最后n天改变状态
[root@centos7 ~]# find -name *.txt |xargs -i cp {} /tmp/ #把TXT文件复制到/tmp/目录下
[root@centos7 ~]# find -name *.txt -exec cp ‘{}’ /tmp/ ; #把TXT文件复制到/tmp/目录下
提示:find命令功能强大应用广泛,常用于查找并执行后续命令,注意exec和xargs的用法。
在计划任务的脚本中,尽量使用绝对路径去执行命令,因为crond程序会在指定的地方去寻找命令