Make shell command substitutions safe with || true (#13279)

Add defensive fallbacks (|| true) to multiple command substitutions to prevent non-zero exits when commands produce no output or are unavailable. Changes touch misc/api.func, misc/build.func and misc/tools.func and cover places like lspci, /proc/cpuinfo parsing, /etc/os-release reads, hostname -I usage, grep reads from vars files and maps, pct config parsing, storage/template lookups, tool version detection, NVIDIA driver version extraction, and MeiliSearch config parsing. These edits do not change functional behavior aside from ensuring the scripts continue running (variables will be empty) instead of failing in stricter shells or when commands return non-zero status.
This commit is contained in:
CanbiZ (MickLesk)
2026-03-25 13:06:21 +01:00
committed by GitHub
parent de356fa8b6
commit 53bc492fdb
3 changed files with 22 additions and 22 deletions

View File

@@ -504,7 +504,7 @@ detect_gpu() {
GPU_PASSTHROUGH="unknown" GPU_PASSTHROUGH="unknown"
local gpu_line local gpu_line
gpu_line=$(lspci 2>/dev/null | grep -iE "VGA|3D|Display" | head -1) gpu_line=$(lspci 2>/dev/null | grep -iE "VGA|3D|Display" | head -1 || true)
if [[ -n "$gpu_line" ]]; then if [[ -n "$gpu_line" ]]; then
# Extract model: everything after the colon, clean up # Extract model: everything after the colon, clean up
@@ -543,7 +543,7 @@ detect_cpu() {
if [[ -f /proc/cpuinfo ]]; then if [[ -f /proc/cpuinfo ]]; then
local vendor_id local vendor_id
vendor_id=$(grep -m1 "vendor_id" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | tr -d ' ') vendor_id=$(grep -m1 "vendor_id" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | tr -d ' ' || true)
case "$vendor_id" in case "$vendor_id" in
GenuineIntel) CPU_VENDOR="intel" ;; GenuineIntel) CPU_VENDOR="intel" ;;
@@ -557,7 +557,7 @@ detect_cpu() {
esac esac
# Extract model name and clean it up # Extract model name and clean it up
CPU_MODEL=$(grep -m1 "model name" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ *//' | sed 's/(R)//g' | sed 's/(TM)//g' | sed 's/ */ /g' | cut -c1-64) CPU_MODEL=$(grep -m1 "model name" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ *//' | sed 's/(R)//g' | sed 's/(TM)//g' | sed 's/ */ /g' | cut -c1-64 || true)
fi fi
export CPU_VENDOR CPU_MODEL export CPU_VENDOR CPU_MODEL
@@ -1347,8 +1347,8 @@ post_addon_to_api() {
# Detect OS info # Detect OS info
local os_type="" os_version="" local os_type="" os_version=""
if [[ -f /etc/os-release ]]; then if [[ -f /etc/os-release ]]; then
os_type=$(grep "^ID=" /etc/os-release | cut -d= -f2 | tr -d '"') os_type=$(grep "^ID=" /etc/os-release | cut -d= -f2 | tr -d '"' || true)
os_version=$(grep "^VERSION_ID=" /etc/os-release | cut -d= -f2 | tr -d '"') os_version=$(grep "^VERSION_ID=" /etc/os-release | cut -d= -f2 | tr -d '"' || true)
fi fi
local JSON_PAYLOAD local JSON_PAYLOAD

View File

@@ -173,10 +173,10 @@ get_current_ip() {
# Check for Debian/Ubuntu (uses hostname -I) # Check for Debian/Ubuntu (uses hostname -I)
if grep -qE 'ID=debian|ID=ubuntu' /etc/os-release; then if grep -qE 'ID=debian|ID=ubuntu' /etc/os-release; then
# Try IPv4 first # Try IPv4 first
CURRENT_IP=$(hostname -I 2>/dev/null | tr ' ' '\n' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -n1) CURRENT_IP=$(hostname -I 2>/dev/null | tr ' ' '\n' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -n1 || true)
# Fallback to IPv6 if no IPv4 # Fallback to IPv6 if no IPv4
if [[ -z "$CURRENT_IP" ]]; then if [[ -z "$CURRENT_IP" ]]; then
CURRENT_IP=$(hostname -I 2>/dev/null | tr ' ' '\n' | grep -E ':' | head -n1) CURRENT_IP=$(hostname -I 2>/dev/null | tr ' ' '\n' | grep -E ':' | head -n1 || true)
fi fi
# Check for Alpine (uses ip command) # Check for Alpine (uses ip command)
elif grep -q 'ID=alpine' /etc/os-release; then elif grep -q 'ID=alpine' /etc/os-release; then
@@ -1704,8 +1704,8 @@ ensure_storage_selection_for_vars_file() {
# Read stored values (if any) # Read stored values (if any)
local tpl ct local tpl ct
tpl=$(grep -E '^var_template_storage=' "$vf" | cut -d= -f2-) tpl=$(grep -E '^var_template_storage=' "$vf" | cut -d= -f2- || true)
ct=$(grep -E '^var_container_storage=' "$vf" | cut -d= -f2-) ct=$(grep -E '^var_container_storage=' "$vf" | cut -d= -f2- || true)
if [[ -n "$tpl" && -n "$ct" ]]; then if [[ -n "$tpl" && -n "$ct" ]]; then
TEMPLATE_STORAGE="$tpl" TEMPLATE_STORAGE="$tpl"
@@ -1840,7 +1840,7 @@ advanced_settings() {
if [[ -n "$BRIDGES" ]]; then if [[ -n "$BRIDGES" ]]; then
while IFS= read -r bridge; do while IFS= read -r bridge; do
if [[ -n "$bridge" ]]; then if [[ -n "$bridge" ]]; then
local description=$(grep -A 10 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep '^#' | head -n1 | sed 's/^#\s*//;s/^[- ]*//') local description=$(grep -A 10 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep '^#' | head -n1 | sed 's/^#\s*//;s/^[- ]*//' || true)
BRIDGE_MENU_OPTIONS+=("$bridge" "${description:- }") BRIDGE_MENU_OPTIONS+=("$bridge" "${description:- }")
fi fi
done <<<"$BRIDGES" done <<<"$BRIDGES"
@@ -3322,7 +3322,7 @@ configure_ssh_settings() {
tag="${tag%\"}" tag="${tag%\"}"
tag="${tag#\"}" tag="${tag#\"}"
local line local line
line=$(grep -E "^${tag}\|" "$MAPFILE" | head -n1 | cut -d'|' -f2-) line=$(grep -E "^${tag}\|" "$MAPFILE" | head -n1 | cut -d'|' -f2- || true)
[[ -n "$line" ]] && printf '%s\n' "$line" >>"$SSH_KEYS_FILE" [[ -n "$line" ]] && printf '%s\n' "$line" >>"$SSH_KEYS_FILE"
done done
;; ;;
@@ -3349,7 +3349,7 @@ configure_ssh_settings() {
tag="${tag%\"}" tag="${tag%\"}"
tag="${tag#\"}" tag="${tag#\"}"
local line local line
line=$(grep -E "^${tag}\|" "$MAPFILE" | head -n1 | cut -d'|' -f2-) line=$(grep -E "^${tag}\|" "$MAPFILE" | head -n1 | cut -d'|' -f2- || true)
[[ -n "$line" ]] && printf '%s\n' "$line" >>"$SSH_KEYS_FILE" [[ -n "$line" ]] && printf '%s\n' "$line" >>"$SSH_KEYS_FILE"
done done
else else
@@ -4050,7 +4050,7 @@ EOF
# Fix Debian 13 LXC template bug where / is owned by nobody:nogroup # Fix Debian 13 LXC template bug where / is owned by nobody:nogroup
# This must be done from the host as unprivileged containers cannot chown / # This must be done from the host as unprivileged containers cannot chown /
local rootfs local rootfs
rootfs=$(pct config "$CTID" | grep -E '^rootfs:' | sed 's/rootfs: //' | cut -d',' -f1) rootfs=$(pct config "$CTID" | grep -E '^rootfs:' | sed 's/rootfs: //' | cut -d',' -f1 || true)
if [[ -n "$rootfs" ]]; then if [[ -n "$rootfs" ]]; then
local mount_point="/var/lib/lxc/${CTID}/rootfs" local mount_point="/var/lib/lxc/${CTID}/rootfs"
if [[ -d "$mount_point" ]] && [[ "$(stat -c '%U' "$mount_point")" != "root" ]]; then if [[ -d "$mount_point" ]] && [[ "$(stat -c '%U' "$mount_point")" != "root" ]]; then
@@ -5142,7 +5142,7 @@ create_lxc_container() {
fi fi
msg_info "Validating storage '$CONTAINER_STORAGE'" msg_info "Validating storage '$CONTAINER_STORAGE'"
STORAGE_TYPE=$(grep -E "^[^:]+: $CONTAINER_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1 | head -1) STORAGE_TYPE=$(grep -E "^[^:]+: $CONTAINER_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1 | head -1 || true)
if [[ -z "$STORAGE_TYPE" ]]; then if [[ -z "$STORAGE_TYPE" ]]; then
msg_error "Storage '$CONTAINER_STORAGE' not found in /etc/pve/storage.cfg" msg_error "Storage '$CONTAINER_STORAGE' not found in /etc/pve/storage.cfg"
@@ -5181,7 +5181,7 @@ create_lxc_container() {
msg_ok "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) validated" msg_ok "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) validated"
msg_info "Validating template storage '$TEMPLATE_STORAGE'" msg_info "Validating template storage '$TEMPLATE_STORAGE'"
TEMPLATE_TYPE=$(grep -E "^[^:]+: $TEMPLATE_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1) TEMPLATE_TYPE=$(grep -E "^[^:]+: $TEMPLATE_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1 || true)
if ! pvesm status -content vztmpl 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$TEMPLATE_STORAGE"; then if ! pvesm status -content vztmpl 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$TEMPLATE_STORAGE"; then
msg_warn "Template storage '$TEMPLATE_STORAGE' may not support 'vztmpl'" msg_warn "Template storage '$TEMPLATE_STORAGE' may not support 'vztmpl'"

View File

@@ -524,12 +524,12 @@ is_tool_installed() {
case "$tool_name" in case "$tool_name" in
mariadb) mariadb)
if command -v mariadb >/dev/null 2>&1; then if command -v mariadb >/dev/null 2>&1; then
installed_version=$(mariadb --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) installed_version=$(mariadb --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)
fi fi
;; ;;
mysql) mysql)
if command -v mysql >/dev/null 2>&1; then if command -v mysql >/dev/null 2>&1; then
installed_version=$(mysql --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) installed_version=$(mysql --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)
fi fi
;; ;;
mongodb | mongod) mongodb | mongod)
@@ -539,7 +539,7 @@ is_tool_installed() {
;; ;;
node | nodejs) node | nodejs)
if command -v node >/dev/null 2>&1; then if command -v node >/dev/null 2>&1; then
installed_version=$(node -v 2>/dev/null | grep -oP '^v\K[0-9]+') installed_version=$(node -v 2>/dev/null | grep -oP '^v\K[0-9]+' || true)
fi fi
;; ;;
php) php)
@@ -4837,7 +4837,7 @@ _setup_nvidia_gpu() {
# Use regex to extract version number (###.##.## or ###.## pattern) # Use regex to extract version number (###.##.## or ###.## pattern)
local nvidia_host_version="" local nvidia_host_version=""
if [[ -f /proc/driver/nvidia/version ]]; then if [[ -f /proc/driver/nvidia/version ]]; then
nvidia_host_version=$(grep -oP '\d{3,}\.\d+(\.\d+)?' /proc/driver/nvidia/version 2>/dev/null | head -1) nvidia_host_version=$(grep -oP '\d{3,}\.\d+(\.\d+)?' /proc/driver/nvidia/version 2>/dev/null | head -1 || true)
fi fi
if [[ -z "$nvidia_host_version" ]]; then if [[ -z "$nvidia_host_version" ]]; then
@@ -7321,7 +7321,7 @@ function setup_meilisearch() {
MEILI_HOST="${MEILISEARCH_HOST:-127.0.0.1}" MEILI_HOST="${MEILISEARCH_HOST:-127.0.0.1}"
MEILI_PORT="${MEILISEARCH_PORT:-7700}" MEILI_PORT="${MEILISEARCH_PORT:-7700}"
MEILI_DUMP_DIR="${MEILISEARCH_DUMP_DIR:-/var/lib/meilisearch/dumps}" MEILI_DUMP_DIR="${MEILISEARCH_DUMP_DIR:-/var/lib/meilisearch/dumps}"
MEILI_MASTER_KEY=$(grep -E "^master_key\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ') MEILI_MASTER_KEY=$(grep -E "^master_key\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ' || true)
# Create dump before update if migration is needed # Create dump before update if migration is needed
local DUMP_UID="" local DUMP_UID=""
@@ -7387,7 +7387,7 @@ function setup_meilisearch() {
# We choose option 2: backup and proceed with warning # We choose option 2: backup and proceed with warning
if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -z "$DUMP_UID" ]]; then if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -z "$DUMP_UID" ]]; then
local MEILI_DB_PATH local MEILI_DB_PATH
MEILI_DB_PATH=$(grep -E "^db_path\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ') MEILI_DB_PATH=$(grep -E "^db_path\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ' || true)
MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}" MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}"
if [[ -d "$MEILI_DB_PATH" ]] && [[ -n "$(ls -A "$MEILI_DB_PATH" 2>/dev/null)" ]]; then if [[ -d "$MEILI_DB_PATH" ]] && [[ -n "$(ls -A "$MEILI_DB_PATH" 2>/dev/null)" ]]; then
@@ -7407,7 +7407,7 @@ function setup_meilisearch() {
# If migration needed and dump was created, remove old data and import dump # If migration needed and dump was created, remove old data and import dump
if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -n "$DUMP_UID" ]]; then if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -n "$DUMP_UID" ]]; then
local MEILI_DB_PATH local MEILI_DB_PATH
MEILI_DB_PATH=$(grep -E "^db_path\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ') MEILI_DB_PATH=$(grep -E "^db_path\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ' || true)
MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}" MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}"
msg_info "Removing old MeiliSearch database for migration" msg_info "Removing old MeiliSearch database for migration"