我可以在 Ubuntu 中通过编辑文件来做到这一点:
/etc/rc.local
并添加:
IP=$(/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}')
echo "IP: $IP" > /etc/issue
在 Arch 中,这个文件不存在“/etc/rc.local”,经过一番搜索后我发现我必须创建这个文件:
/etc/systemd/system/rc-local.service
内容:
[Unit]
Description=/etc/rc.local compatibility
[Service]
Type=oneshot
ExecStart=/etc/rc.local
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99
[Install]
WantedBy=multi-user.target
然后创建“/etc/rc.local”。
内容:
IP=$(/sbin/ip route get 1 | awk '{print $NF;exit}')
echo "IP: $IP" > /etc/issue
exit 0
然后使其可执行:
sudo chmod +x /etc/rc.local
最后开始/测试:
sudo systemctl start rc-local.service
收到错误:
Job for rc-local.service failed because the control process exited with error code.
See "systemctl status rc-local.service" and "journalctl -xe" for details.
输出systemctl status rc-local.service
:
* rc-local.service - /etc/rc.local Compatibility
Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Fri 2016-06-10 02:52:17 AST; 1min 59s ago
Process: 760 ExecStart=/etc/rc.local (code=exited, status=203/EXEC)
Jun 10 02:52:17 maro systemd[1]: Starting /etc/rc.local Compatibility...
Jun 10 02:52:17 maro systemd[1]: rc-local.service: Control process exited, code=exited status=203
Jun 10 02:52:17 maro systemd[1]: Failed to start /etc/rc.local Compatibility.
Jun 10 02:52:17 maro systemd[1]: rc-local.service: Unit entered failed state.
Jun 10 02:52:17 maro systemd[1]: rc-local.service: Failed with result 'exit-code'.
输出journalctl -xe
:
-- Unit rc-local.service has begun starting up.
Jun 10 02:52:17 maro systemd[760]: rc-local.service: Failed at step EXEC spawning /etc/rc.local: Exec format error
-- Subject: Process /etc/rc.local could not be executed
-- Defined-By: systemd
更新:
- 添加
#!/bin/bash
到/etc/rc.local
sudo systemctl daemon-reload
sudo systemctl start rc-local.service
- 现在我没有收到任何错误!但是:
sudo systemctl status rc-local.service
输出:rc-local.service - /etc/rc.local Compatibility Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: disabled) Active: inactive (dead) since Fri 2016-06-10 13:13:04 AST; 3s ago Process: 488 ExecStart=/etc/rc.local (code=exited, status=0/SUCCESS)
Jun 10 13:13:04 maro systemd[1]: Starting /etc/rc.local Compatibility... Jun 10 13:13:04 maro systemd[1]: Started /etc/rc.local Compatibility.
尝试重新启动,登录前显示:
rtnetlink answers network is unreachable
在登录屏幕上:它仅显示“IP:”,而不显示机器 IP。一旦登录并 ping google,互联网就可以正常工作,并且可以通过 LAN 访问机器。
sudo env -i /etc/rc.local
= 无输出ip route get 1 | awk '{print $NF;exit}'
用于/etc/rc.local
= 192.168.0.103
输出nav
:
XDG_SESSION_ID=c2
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=192.168.0.100 64436 22
SSH_TTY=/dev/pts/0
USER=maro
MAIL=/var/spool/mail/maro
PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
PWD=/home/maro
LANG=C
SHLVL=1
HOME=/home/maro
LOGNAME=maro
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
SSH_CONNECTION=192.168.0.100 64436 192.168.0.103 22
XDG_RUNTIME_DIR=/run/user/1000
_=/usr/bin/env
已编辑/etc/systemd/system/rc-local.service
:删除了 ExecStart 后的四个设置。我还尝试更改:
Type=forking
状态仍然显示:Active: inactive (dead)
答案1
我 99% 确定这是因为您没有在脚本中调用解释器。
/etc/rc.local:
#!/bin/bash
IP=$(/sbin/ip route get 1 | awk '{print $NF;exit}')
echo "IP: $IP" > /etc/issue
exit 0
这可能会奏效。许多人还在系统文件中明确调用 bash;我修改了您的服务文件。我在下面提到了这一点,但其中 4 个设置是不必要的(据我所知),我也在这里删除了它们:
/etc/systemd/system/rc-local.service:
[Unit]
Description=/etc/rc.local compatibility
[Service]
Type=oneshot
ExecStart=/bin/bash /etc/rc.local
[Install]
WantedBy=multi-user.target
您也应该使用 awk 的完整路径,但是那将是另一个错误 - 您还没有深入到脚本的那么深。
如果这不能解决问题,您必须逐步检查每个部分,看看哪些部分可以单独工作。systemd 环境非常稀疏(类似于从 cron 启动的东西,但环境较少)。总是由于某些环境设置始终处于设置状态,我们忘记了它甚至需要设置,因此工作停止了。因此,请尝试隔离与此相关的问题。以下是一些隔离步骤:
/etc/rc.local
直接从终端执行(使用 sudo 或每个步骤在 root shell 中执行) 。如果可行,则尝试执行它,
env -i /etc/rc.local
如果它不起作用,您可以尝试一次传递一个环境值,或者让您的脚本“强力”设置它们(非常不受欢迎,但如果您愿意,您可以转储env
“正常”shell 中的输出,env | sed 's/^/export /g' | sed 's/=/='/g' | sed -e 's/$/'/g' > env_values.sh
并在脚本中明确设置这些值..您确实需要稍微清理一下列表 - 它将具有 ssh 连接值和其他事件驱动的条目,这些条目可能不会破坏任何东西,但肯定不会有任何帮助)。如果不是这样,因为无论你如何执行 rc.local 它都会正常工作,我会删除你的 systemd 服务文件。试试不用它们。
- 退出后的剩余设置在这里与此无关 - 这与使用它来调用生成守护进程的一次性脚本有关。
- tty 设置是非常特殊的情况,并且不需要。
- 超时设置为 0 可能会导致电源循环期间系统挂起。
- SysVStartPriority 在 systemd ver > 218+ 上已弃用;arch 至少在 ver 229 上。
尝试使用@reboot 定时任务。非常相似的环境,但我发现它不那么“挑剔”。@reboot 取代了正常的 5 星号计时方法(例如,只需输入 @reboot 而不是 0 0 0 * *),并且每次启动时都会调用您的脚本。如果您在设置 cronjob 方面需要更多帮助,我绝对可以提供更多详细信息。
我看不出你获取局域网 IP 的方法有什么问题。如果出现任何问题,可以尝试以下另一种方法。你的方法可能更好。依赖关系更少,而且肯定更简洁,但我已经使用这种方法很多年了,没有出现问题:
iprgx='(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
cat /etc/hostname | /usr/bin/host -4r | grep -Eo "$iprgx"
如果所有这些都失败了,那么你必须阅读 systemd 文档……你可能已经发现它的字数非常多,具体信息却少得可怜。即使这些想法行不通,也请告诉我你发现了什么——无论如何,结果中可能都有线索。
更新
根据您的更新,对服务的更改允许脚本正常运行。您获得的状态对于一次性服务来说是正常的 - systemd 服务实际上专注于启动的守护进程,而您没有这样做 - 因此(简化了很多)基本上它说它处于非活动状态只是意味着脚本没有继续运行,它没有安排运行,并且它没有产生 systemd 正在跟踪的任何进程 - 这一切都是正确的,没有问题。它显示它最近刚刚运行并以 SUCCESS 退出,这意味着它正在运行。
第二个问题是相对时间。简单的答案是,您需要通过在 [Unit] 下添加以下两个条目来更改服务文件。这可能只是工作。如果没有,请继续阅读。
[Unit]
Wants=network-online.target
After=network-online.target
关于这个问题,有一篇很好的文章stackchange 他们似乎已经涵盖了所有可能出错的方式以及以错误的方式正确运行的方式...我不会费心去传达它 - 只需直接从一位明显的大师那里获得它。
另一种方法的好处是激怒了 systemd 的粉丝
如果出于某种原因,这种方法变得困难或不可能,那么当我的 systemd 耐心耗尽时,我通常会求助于一种不那么优雅的蛮力方法:
您可以修改脚本以等待 IP 地址本身可用,而不是纠结于先来后来的计时问题。这是一种 hack,因为它故意重新实现内置于 systemd 中的功能,但我可能会这样做。
我更新了这个脚本(尝试运行它并发现了几个问题)。这个在我的系统上运行良好。我在 sleep 调用中使用了 C 函数语法,并且忘记从 getIP 实际返回任何内容;两者都已修复。
/etc/rc.local
#!/bin/bash
iprgx='(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
# I put this into a function since you will be looping on it.
# the error you are seeing is from the ip call - I pipe the error to
# /dev/null to get rid of that annoyance.
getIP() {
echo "IP=$(/sbin/ip route get 1 2>/dev/null | awk '{print $NF;exit}' | grep -Eo "$iprgx")"
}
# watchdog timer - bail if it doesn't resolve after some delta-T
wdTimer=1
IP=$(getIP)
#echo "($wdTimer) IP: $IP"
while [ "$IP" == "" ]; do
# There's nothing special about .5 seconds - just seemed reasonable
sleep 0.5
IP=$(getIP)
#echo "($wdTimer) IP: $IP"
((wdTimer++))
# Arbitrarily chosen timeout of 20 * 0.5 = 10 seconds
# You can have it wait as long as you want. I suggest not
# setting the sleep time too low as you'll be hammering on the
# ip utility fairly hardly in that case; not a huge deal regardless
# I also had it log something to the syslog - your mileage may vary
# with logger - there are alternative ways to do that.
if [ "$wdTimer" -gt "20" ]; then
# timeout
logger -s "Timed out attempting to acquire LAN IP in rc.local"
exit 1
fi
done
#echo "IP: $IP" #> /etc/issue
exit 0
是的,我一直在使用正则表达式 $iprgx——非常有用。
答案2
在CentOS 7和Debian 8(也可能是其他的),只需将以下行附加到/etc/issue
My IP address: \4
这将解析为机器的 IPv4 地址。如果您有多个网络接口,并且想要选择一个特定的,您可以使用
My IP address: \4{eth0}