3
我一直在使用內置的printf
bash將字符串填充到特定寬度時出現「off-by-one」問題。內置printf bash可能的填充bug
看看下面的代碼:
#!/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
行使用相同的填充值?
對於它的價值,我的bash的版本是:
GNU bash, version 4.3.42(1)-release (x86_64-redhat-linux-gnu)
謝謝!
它沒有'大膽'和類似的東西工作嗎? – choroba
刪除這些'printf'行中的所有'tput'調用可以解決這個問題。然而,我不明白,所有的'tput'調用都是用粗體和顏色來平衡的,沒有一個調用'tput'的次數不是其他的。 –
看起來問題可能在於'tput'將'setaf'命令簡單地轉換爲'\ 033 [0; xxxm',其中'xxx'在其他行中是'246',而在有問題的行中是'32'。如果是這樣,那麼這將解釋一個差異,因爲'32'是2個字符,而'246'是3個字符。 –