在使用内置的 printf
bash 将字符串填充到特定宽度时,我遇到了一些“逐一”问题。
采用以下代码:
#!/bin/bash
# vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
# Only display motd if tty and not sudoing as root
[ "$PS1" ] && [ "$EUID" -ne 0 ] || return 0
# Run the entire function in its own subshell.
#
# The local keyword in functions prevents inheriting values.
# The subshell prevents exporting them.
#
# Technically, local prevents exporting too. Only the vars that
# could be used before initialized need to be declared local to
# prevent the parent env from leaking into it.
(
MOTD_DEFAULT_VALUE="-"
function show_motd() {
local MOTD_AVAILABILITY_ZONE \
MOTD_INSTANCE_ID \
MOTD_INSTANCE_TYPE \
MOTD_VPC_ID \
MOTD_PUBLIC_IP
MOTD_AWS_METADATA_URL="http://169.254.169.254/latest/meta-data"
# Detect if inside AWS
MOTD_INTERFACE_PRIMARY_MAC="$(curl -s --connect-timeout 0.1 --max-time 0.1 ${MOTD_AWS_METADATA_URL}/network/interfaces/macs/ 2>/dev/null | sed -n 1p | cut -c-17)"
if [ -n "${MOTD_INTERFACE_PRIMARY_MAC}" ]; then
MOTD_AVAILABILITY_ZONE="$(curl -s ${MOTD_AWS_METADATA_URL}/placement/availability-zone 2>/dev/null)"
MOTD_INSTANCE_ID="$(curl -s ${MOTD_AWS_METADATA_URL}/instance-id 2>/dev/null)"
MOTD_INSTANCE_TYPE="$(curl -s ${MOTD_AWS_METADATA_URL}/instance-type 2>/dev/null)"
MOTD_VPC_ID="$(curl -s ${MOTD_AWS_METADATA_URL}/network/interfaces/macs/${MOTD_INTERFACE_PRIMARY_MAC}/vpc-id 2>/dev/null)"
[[ "${MOTD_VPC_ID}" == *'Not Found'* ]] && MOTD_VPC_ID=""
MOTD_PUBLIC_IP="$(curl -s ${MOTD_AWS_METADATA_URL}/public-ipv4 2>/dev/null)"
[[ "${MOTD_PUBLIC_IP}" == *'Not Found'* ]] && MOTD_PUBLIC_IP=""
fi
MOTD_OS="$(cat /etc/system-release | sed 's/ release / /g' 2>/dev/null)"
[ -z "${MOTD_OS}" ] && MOTD_OS="$(cat /etc/os-release | grep 'PRETTY_NAME' | cut -d\" -f2 2>/dev/null)"
MOTD_HOSTNAME="$(hostnamectl --static 2>/dev/null)"
if [ -z "${MOTD_HOSTNAME}" ]; then
MOTD_HOSTNAME="$(hostnamectl --transient 2>/dev/null)"
if [ -z "${MOTD_HOSTNAME}" ]; then
MOTD_HOSTNAME="$(hostname 2>/dev/null)"
fi
fi
if [ -z "${MOTD_PUBLIC_IP}" ]; then
MOTD_PUBLIC_IP="$(ip -4 addr show scope global primary | sed -n 5p | cut -d\ -f6 | cut -d/ -f1 2>/dev/null)"
fi
MOTD_GATEWAY_IP="$(curl -s http://checkip.amazonaws.com 2>/dev/null)"
MOTD_PRIVATE_IP="$(ip -4 addr show scope global primary | sed -n 2p | cut -d\ -f6 | cut -d/ -f1 2>/dev/null)"
MOTD_TOTAL_CPUS="$(grep processor /proc/cpuinfo | wc -l 2>/dev/null)"
MOTD_TOTAL_DISKS="$(df -h | grep '^\/dev\/' | wc -l 2>/dev/null)"
MOTD_TOTAL_DISK_USED="$(df -h | grep '^\/dev/' | sed -n 1p | awk '{print $3, "/", $2, "(" $5 ")"}' 2>/dev/null)"
MOTD_TOTAL_MEMORY="$(free -h | awk '{print $2}' | sed -n 2p 2>/dev/null)"
if [ "${MOTD_PUBLIC_IP}" = "${MOTD_GATEWAY_IP}" ]; then
MOTD_GATEWAY_IP=""
fi
[ -z "${MOTD_AVAILABILITY_ZONE}" ] && MOTD_AVAILABILITY_ZONE="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_GATEWAY_IP}" ] && MOTD_GATEWAY_IP="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_HOSTNAME}" ] && MOTD_HOSTNAME="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_INSTANCE_ID}" ] && MOTD_INSTANCE_ID="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_INSTANCE_TYPE}" ] && MOTD_INSTANCE_TYPE="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_OS}" ] && MOTD_OS="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_PRIVATE_IP}" ] && MOTD_PRIVATE_IP="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_PUBLIC_IP}" ] && MOTD_PUBLIC_IP="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_TOTAL_CPUS}" ] && MOTD_TOTAL_CPUS="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_TOTAL_DISKS}" ] && MOTD_TOTAL_DISKS="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_TOTAL_DISK_USED}" ] && MOTD_TOTAL_DISK_USED="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_TOTAL_MEMORY}" ] && MOTD_TOTAL_MEMORY="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_VPC_ID}" ] && MOTD_VPC_ID="${MOTD_DEFAULT_VALUE}"
printf "$(tput sgr0;tput setaf 124)%-$(tput cols)s$(tput sgr0)\n%-$(tput cols)s\n" \
"This system is operated and monitored by a private party." ""
printf " %sHostname: %s\n" "$(tput bold;tput setaf 216)" "$(tput sgr0;tput setaf 180;echo ${MOTD_HOSTNAME})"
printf " %sOS: %-47s " "$(tput bold;tput setaf 75)" "$(tput sgr0;tput setaf 32;echo ${MOTD_OS})"
printf " %sTotal CPUs: %s\n" "$(tput bold;tput setaf 48)" "$(tput sgr0;tput setaf 78;echo ${MOTD_TOTAL_CPUS})"
printf " %sPublic IP: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_PUBLIC_IP})"
printf " %sTotal Memory: %s\n" "$(tput bold;tput setaf 48)" "$(tput sgr0;tput setaf 78;echo ${MOTD_TOTAL_MEMORY})"
printf " %sPrivate IP: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_PRIVATE_IP})"
printf " %sTotal Disks: %s\n" "$(tput bold;tput setaf 48)" "$(tput sgr0;tput setaf 78;echo ${MOTD_TOTAL_DISKS})"
printf " %sGateway IP: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_GATEWAY_IP})"
printf " %sRoot Vol. Used: %s\n" "$(tput bold;tput setaf 48)" "$(tput sgr0;tput setaf 78;echo ${MOTD_TOTAL_DISK_USED})"
printf "%sInstance Id: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_INSTANCE_ID})"
printf " %sAvail. Zone: %s\n" "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_AVAILABILITY_ZONE})"
printf " %sVPC Id: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_VPC_ID})"
printf " %sInstance Type: %s\n" "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_INSTANCE_TYPE})"
printf "$(tput sgr0)%-$(tput cols)s\n" ""
}
show_motd || true
)
请特别注意以下行:
printf " %sOS: %-47s " "$(tput bold;tput setaf 75)" "$(tput sgr0;tput setaf 32;echo ${MOTD_OS})"
%-47s
与其余部分的 %-48s
不同,因为这似乎解决了我正在描述的问题,但是如果我将其恢复到匹配其余部分,因此所有行都独占使用 %-48s
,会发生以下问题:
This system is operated and monitored by a private party.
Hostname: nova.localdomain
OS: Fedora 24 (Twenty Four) Total CPUs: 6
Public IP: - Total Memory: 7.8G
Private IP: 192.168.1.100 Total Disks: 2
Gateway IP: - Root Vol. Used: 11G / 32G (36%)
Instance Id: - Avail. Zone: -
VPC Id: - Instance Type: -
请注意 Total CPUs:
单元格如何被向右推一个字符,但在该行上使用 %-47s
解决了这个问题,因此它与该列中的其余单元格。
我想知道是否有人可以向我解释这是为什么以及如何解决这个问题以便所有 printf
行都使用相同的填充值?
就其值(value)而言,我的 bash 版本是:
GNU bash, version 4.3.42(1)-release (x86_64-redhat-linux-gnu)
谢谢!
最佳答案
经过反复试验,我自己解决了这个问题。
此问题是由在 printf
行中调用 tput
创建的丰富格式引起的。由于根据颜色 ID 的字符串长度生成的格式字符串长度不同(例如 246(长度为 3)与 32(长度为 2)),这导致了对齐问题。
上述原文件的补丁如下:
diff --git a/motdA.sh b/motdB.sh
index b73c6ab..fa3e609 100644
--- a/motdA.sh
+++ b/motdB.sh
@@ -42,6 +42,8 @@
MOTD_OS="$(cat /etc/system-release | sed 's/ release / /g' 2>/dev/null)"
[ -z "${MOTD_OS}" ] && MOTD_OS="$(cat /etc/os-release | grep 'PRETTY_NAME' | cut -d\" -f2 2>/dev/null)"
+ MOTD_OS_COLOR_B="$(cat /etc/os-release | grep 'ANSI_COLOR' | cut -d\" -f2 2>/dev/null)"
+
MOTD_HOSTNAME="$(hostnamectl --static 2>/dev/null)"
if [ -z "${MOTD_HOSTNAME}" ]; then
MOTD_HOSTNAME="$(hostnamectl --transient 2>/dev/null)"
@@ -70,6 +72,7 @@
[ -z "${MOTD_HOSTNAME}" ] && MOTD_HOSTNAME="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_INSTANCE_ID}" ] && MOTD_INSTANCE_ID="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_INSTANCE_TYPE}" ] && MOTD_INSTANCE_TYPE="${MOTD_DEFAULT_VALUE}"
+ [ -z "${MOTD_OS_COLOR_B}" ] && MOTD_OS_COLOR_B="0;32"
[ -z "${MOTD_OS}" ] && MOTD_OS="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_PRIVATE_IP}" ] && MOTD_PRIVATE_IP="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_PUBLIC_IP}" ] && MOTD_PUBLIC_IP="${MOTD_DEFAULT_VALUE}"
@@ -79,20 +82,25 @@
[ -z "${MOTD_TOTAL_MEMORY}" ] && MOTD_TOTAL_MEMORY="${MOTD_DEFAULT_VALUE}"
[ -z "${MOTD_VPC_ID}" ] && MOTD_VPC_ID="${MOTD_DEFAULT_VALUE}"
+ MOTD_OS_COLOR_A="1;${MOTD_OS_COLOR_B:2}"
+
+ MOTD_PADDING="48" # Arbitrary length
+ MOTD_PADDING_OS="$((${MOTD_PADDING}-${#MOTD_OS_COLOR_B}-6))" # 6 comes from length of "\033[m"
+
printf "$(tput sgr0;tput setaf 124)%-$(tput cols)s$(tput sgr0)\n%-$(tput cols)s\n" \
"This system is operated and monitored by a private party." ""
printf " %sHostname: %s\n" "$(tput bold;tput setaf 216)" "$(tput sgr0;tput setaf 180;echo ${MOTD_HOSTNAME})"
- printf " %sOS: %-47s " "$(tput bold;tput setaf 75)" "$(tput sgr0;tput setaf 32;echo ${MOTD_OS})"
+ printf " %sOS: %-${MOTD_PADDING_OS}s " "$(echo -en "\033[${MOTD_OS_COLOR_A}m")" "$(echo -en "\033[${MOTD_OS_COLOR_B}m${MOTD_OS}")"
printf " %sTotal CPUs: %s\n" "$(tput bold;tput setaf 48)" "$(tput sgr0;tput setaf 78;echo ${MOTD_TOTAL_CPUS})"
- printf " %sPublic IP: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_PUBLIC_IP})"
+ printf " %sPublic IP: %-${MOTD_PADDING}s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_PUBLIC_IP})"
printf " %sTotal Memory: %s\n" "$(tput bold;tput setaf 48)" "$(tput sgr0;tput setaf 78;echo ${MOTD_TOTAL_MEMORY})"
- printf " %sPrivate IP: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_PRIVATE_IP})"
+ printf " %sPrivate IP: %-${MOTD_PADDING}s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_PRIVATE_IP})"
printf " %sTotal Disks: %s\n" "$(tput bold;tput setaf 48)" "$(tput sgr0;tput setaf 78;echo ${MOTD_TOTAL_DISKS})"
- printf " %sGateway IP: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_GATEWAY_IP})"
+ printf " %sGateway IP: %-${MOTD_PADDING}s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_GATEWAY_IP})"
printf " %sRoot Vol. Used: %s\n" "$(tput bold;tput setaf 48)" "$(tput sgr0;tput setaf 78;echo ${MOTD_TOTAL_DISK_USED})"
- printf "%sInstance Id: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_INSTANCE_ID})"
+ printf "%sInstance Id: %-${MOTD_PADDING}s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_INSTANCE_ID})"
printf " %sAvail. Zone: %s\n" "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_AVAILABILITY_ZONE})"
- printf " %sVPC Id: %-48s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_VPC_ID})"
+ printf " %sVPC Id: %-${MOTD_PADDING}s " "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_VPC_ID})"
printf " %sInstance Type: %s\n" "$(tput bold;tput setaf 250)" "$(tput sgr0;tput setaf 246;echo ${MOTD_INSTANCE_TYPE})"
printf "$(tput sgr0)%-$(tput cols)s\n" ""
}
感谢所有做出贡献的人!
关于string - 内置 printf bash 的可能填充错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39214425/