From ec1ea0b539213c4cd024486160ba303621426d48 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Wed, 25 Mar 2026 08:59:11 +0100 Subject: [PATCH] Make shell command substitutions safe with || true 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. --- misc/api.func | 10 +++++----- misc/build.func | 20 ++++++++++---------- misc/tools.func | 14 +++++++------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/misc/api.func b/misc/api.func index c90731091..e3d997802 100644 --- a/misc/api.func +++ b/misc/api.func @@ -504,7 +504,7 @@ detect_gpu() { GPU_PASSTHROUGH="unknown" 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 # Extract model: everything after the colon, clean up @@ -543,7 +543,7 @@ detect_cpu() { if [[ -f /proc/cpuinfo ]]; then 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 GenuineIntel) CPU_VENDOR="intel" ;; @@ -557,7 +557,7 @@ detect_cpu() { esac # 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 export CPU_VENDOR CPU_MODEL @@ -1347,8 +1347,8 @@ post_addon_to_api() { # Detect OS info local os_type="" os_version="" if [[ -f /etc/os-release ]]; then - os_type=$(grep "^ID=" /etc/os-release | cut -d= -f2 | tr -d '"') - os_version=$(grep "^VERSION_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 '"' || true) fi local JSON_PAYLOAD diff --git a/misc/build.func b/misc/build.func index 636f6b164..88221f8c4 100644 --- a/misc/build.func +++ b/misc/build.func @@ -173,10 +173,10 @@ get_current_ip() { # Check for Debian/Ubuntu (uses hostname -I) if grep -qE 'ID=debian|ID=ubuntu' /etc/os-release; then # 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 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 # Check for Alpine (uses ip command) elif grep -q 'ID=alpine' /etc/os-release; then @@ -1704,8 +1704,8 @@ ensure_storage_selection_for_vars_file() { # Read stored values (if any) local tpl ct - tpl=$(grep -E '^var_template_storage=' "$vf" | cut -d= -f2-) - ct=$(grep -E '^var_container_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- || true) if [[ -n "$tpl" && -n "$ct" ]]; then TEMPLATE_STORAGE="$tpl" @@ -1840,7 +1840,7 @@ advanced_settings() { if [[ -n "$BRIDGES" ]]; then while IFS= read -r bridge; do 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:- }") fi done <<<"$BRIDGES" @@ -3322,7 +3322,7 @@ configure_ssh_settings() { tag="${tag%\"}" tag="${tag#\"}" 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" done ;; @@ -3349,7 +3349,7 @@ configure_ssh_settings() { tag="${tag%\"}" tag="${tag#\"}" 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" done else @@ -4050,7 +4050,7 @@ EOF # Fix Debian 13 LXC template bug where / is owned by nobody:nogroup # This must be done from the host as unprivileged containers cannot chown / 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 local mount_point="/var/lib/lxc/${CTID}/rootfs" if [[ -d "$mount_point" ]] && [[ "$(stat -c '%U' "$mount_point")" != "root" ]]; then @@ -5142,7 +5142,7 @@ create_lxc_container() { fi 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 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_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 msg_warn "Template storage '$TEMPLATE_STORAGE' may not support 'vztmpl'" diff --git a/misc/tools.func b/misc/tools.func index 62bc83b6a..56b18d8a6 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -524,12 +524,12 @@ is_tool_installed() { case "$tool_name" in mariadb) 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 ;; mysql) 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 ;; mongodb | mongod) @@ -539,7 +539,7 @@ is_tool_installed() { ;; node | nodejs) 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 ;; php) @@ -4837,7 +4837,7 @@ _setup_nvidia_gpu() { # Use regex to extract version number (###.##.## or ###.## pattern) local nvidia_host_version="" 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 if [[ -z "$nvidia_host_version" ]]; then @@ -7321,7 +7321,7 @@ function setup_meilisearch() { MEILI_HOST="${MEILISEARCH_HOST:-127.0.0.1}" MEILI_PORT="${MEILISEARCH_PORT:-7700}" 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 local DUMP_UID="" @@ -7387,7 +7387,7 @@ function setup_meilisearch() { # We choose option 2: backup and proceed with warning if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -z "$DUMP_UID" ]]; then 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}" 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 [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -n "$DUMP_UID" ]]; then 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}" msg_info "Removing old MeiliSearch database for migration"