错误
在具有 4GB RAM 的 RaspberryPi 上运行适用于 armhf 架构的新 Ubuntu Server 20.04.2 LTS 32 位服务器操作系统时sudo apt update
,我遇到以下错误:sudo apt upgrade
为了sudo apt update
:
E:http://ports.ubuntu.com.../focal-updates/Inrelease 的发布文件尚未生效(在 113 天 22 小时 43 分钟内无效)。不会应用此存储库的更新。
为了sudo apt upgrade
:
等待缓存锁定:无法获取锁定 /var/lib/dpkg/lock-frontend。它由进程 3381 (unattended-upgr) 持有。
代码
下面的代码首先检查互联网是否可用,如果不可用,则检查 wifi ssid 和密码是否已添加到配置中,如果没有,则提示用户输入,然后激活这些设置,直到建立互联网连接。然后它执行和sudo apt update
命令sudo apt upgrade
。
# Verify internet access is available
while [ $(ping -q -w1 -c1 google.com &>/dev/null && echo online || echo offline) == offline ]
do
sleep 1
# get wifi module
module=$(ls /sys/class/net)
module_list=($module)
wlan_module=${module_list[-1]}
echo $wlan_module
# get wifi configuration file
config_filename=$(ls /etc/netplan)
echo $config_filename
config_filepath="/etc/netplan/$config_filename"
# check if the wifi is already added.
if ! grep -q "$wlan_module" "$config_filepath"; then
echo "have to add wifi"
# ask wifi pwd ssid
read -p "What is the wifi ssid you want to connect to(Case sensitive)?" ssid
# ask wifi pwd
read -p "What is the wifi pwd?" pwd
# append content
echo " wifis:" | sudo tee -a $config_filepath
echo " wlan0:" | sudo tee -a $config_filepath
echo " dhcp4: true" | sudo tee -a $config_filepath
echo " optional: true" | sudo tee -a $config_filepath
echo " access-points:" | sudo tee -a $config_filepath
echo " \"$ssid\":" | sudo tee -a $config_filepath
echo " password: \"$pwd\"" | sudo tee -a $config_filepath
# generate a config file
sudo netplan generate
# apply the config file
sudo netplan apply
fi
done
# set timezone based on ip
export tz=`wget -qO - http://geoip.ubuntu.com/lookup | sed -n -e 's/.*<TimeZone>\(.*\)<\/TimeZone>.*/\1/p'` && timedatectl set-timezone $tz
export tz=`timedatectl status| grep Timezone | awk '{print $2}'`
# Verify timezone is set correctly.
timedatectl status
yes | sudo apt update
read -p "Update completed <type enter>" next
yes | sudo apt upgrade
read -p "Upgrade completed <type enter>" next
代码使用以下方式执行:
sudo mkdir /media/usbstick
sudo mount /dev/sda1 /media/usbstick
/media/usbstick/.first_run.sh
时区详细信息
为了回应评论,我添加了自动设置时区的代码,并且手动验证了时区是否设置正确。
假设
我认为这是因为 Ubuntu 服务器正在后台自动执行某种更新/升级,从而阻止我sudo apt upgrade
同时运行该命令。
问题
sudo apt upgrade
因此,当我手动终止阻止命令的进程时,sudo kill -9 <process_id>
我能够成功运行该sudo apt upgrade
命令。但是,我可以想象这不是确保升级命令成功完成的最佳方法。所以我目前的方法是编写一个while-loop
扫描命令输出sudo apt upgrade
直到它产生成功输出的程序。然而,这感觉就像重新发明轮子,我可以想象可能存在更好的方法来解决这个问题。因此,我想问:
如何sudo apt upgrade
在新安装的 Ubuntu Server 20.04 LTS 32 位服务器上安全、自动地运行命令,以便我的 Ubuntu Server 后续脚本的其余部分能够正确完成?
答案1
我当前的实现由两个 while 循环组成,它们运行两个sudo apt update
和sudo apt upgrade
命令,直到验证它们各自的输出。它远非优雅,但似乎有效。增强的first_run.sh
脚本包含以下内容:
# Assumes both strings have equal lengths
equal_strings() {
left=$1
right=$2
# Initialise the default test result to false
test_result=false
# Set the test result to true if the left and right string are equal
if [ "$left" = "$right" ]; then
echo "Strings are equal."
test_result=true
else
echo "Strings are not equal."
fi
# Output true or false to pass the equality test result to parent function
echo $test_result
}
# Assumes the actual result is shorter than the allowed result
right_is_in_tail_of_left() {
left=$1
right=$2
right_size=${#right}
left_tail_chars=$(echo -n $left | tail -c $right_size)
# Output true or false to pass test result to parent function
echo $(equal_strings "$left_tail_chars" "$right")
}
# Makes the main script runnable, removes the log file and runs main file.
actual_result_has_any_allowed_result_in_tail() {
# declare default function output
test_result=false
# get the actual result
actual_result=$1
shift # Shift all arguments to the left (original $1 gets lost)
# get the list of allowed results and list size
allowed_results=("$@")
list_size=${#allowed_results}
# Only engage this function if the list size is greater than 1
if [ $list_size -gt 1 ]; then echo "error";
# if the actual result is in the acceptable list ensure function returns true
for allowed_result in "${allowed_results[@]}"
do
if [ $test_result != true ]; then
# compute lengths of result strings
allowed_result_size=${#allowed_result}
actual_result_size=${#actual_result}
# TODO: remove this if condition and directly go to Else by switching lt to ge
if [ $actual_result_size -lt $allowed_result_size ]; then echo "error";
echo "The actual size is:"
echo $actual_result_size
echo "WHEREAS allowed_result_size="
echo $allowed_result_size
echo "so actual is smaller than allowed, so do nothing"
else
# test if left string is in the tail of the allowed result string
# TODO: include contains option in separate function
temp_test_result=$(right_is_in_tail_of_left "$actual_result" "$allowed_result");
if [ $(echo -n $temp_test_result | tail -c 4) == true ]; then
test_result=true
fi
fi
fi
done
fi
# Ensure the last 4/5 characters of the output of this function contains the true false evaluation.
echo $test_result
}
# Verify internet access is available
while [ $(ping -q -w1 -c1 google.com &>/dev/null && echo online || echo offline) == offline ]
do
sleep 1
# get wifi module
module=$(ls /sys/class/net)
module_list=($module)
wlan_module=${module_list[-1]}
echo $wlan_module
# get wifi configuration file
config_filename=$(ls /etc/netplan)
echo $config_filename
config_filepath="/etc/netplan/$config_filename"
# check if the wifi is already added.
if ! grep -q "$wlan_module" "$config_filepath"; then
echo "have to add wifi"
# ask wifi pwd ssid
read -p "What is the wifi ssid you want to connect to(Case sensitive)?" ssid
# ask wifi pwd
read -p "What is the wifi pwd?" pwd
# append content
echo " wifis:" | sudo tee -a $config_filepath
echo " wlan0:" | sudo tee -a $config_filepath
echo " dhcp4: true" | sudo tee -a $config_filepath
echo " optional: true" | sudo tee -a $config_filepath
echo " access-points:" | sudo tee -a $config_filepath
echo " \"$ssid\":" | sudo tee -a $config_filepath
echo " password: \"$pwd\"" | sudo tee -a $config_filepath
# generate a config file
sudo netplan generate
# apply the config file
sudo netplan apply
fi
done
# https://askubuntu.com/questions/323131/setting-timezone-from-terminal
echo "Setting TimeZone..."
export tz=`wget -qO - http://geoip.ubuntu.com/lookup | sed -n -e 's/.*<TimeZone>\(.*\)<\/TimeZone>.*/\1/p'` && timedatectl set-timezone $tz
export tz=`timedatectl status| grep Timezone | awk '{print $2}'`
echo "TimeZone set to $tz"
# A loop that checks whether the output of the update command is as expected after successfull completion.
check_output_update_command() {
#test_result=false
while [[ $test_result != true ]]
do
update_output=$(yes | sudo apt update)
echo $update_output
allowed_results=("Reading package lists... Building dependency tree... Reading state information... All packages are up to date."
"packages can be upgraded. Run 'apt list --upgradable' to see them."
)
test_result=$(actual_result_has_any_allowed_result_in_tail "$update_output" "${allowed_results[@]}")
test_result=${test_result: -4}
echo $test_result
done
}
check_output_update_command "$@"
read -p "Succesfully completed update command <type enter>" next
# A loop that checks whether the output of the upgrade command is as expected after successfull completion.
check_output_upgrade_command() {
#output_ending=false
while [[ $output_ending != " upgraded." ]]
do
upgrade_output=$(yes | sudo apt upgrade)
echo $upgrade_output
#output_ending=$(tail -c 11 $upgrade_output)
output_ending=${upgrade_output: -10}
echo $output_ending
done
}
check_output_upgrade_command "$@"
read -p "Succesfully completed upgrade command <type enter>" next
并且可以使用以下命令执行:
sudo mkdir /media/usbstick
sudo mount /dev/sda1 /media/usbstick
/media/usbstick/.first_run.sh