x
我有一个带有尾随换行符的变量。
printf -v x 'hello\n'
如何判断 的最后一个字符是否x
是\n
?
答案1
您描述的是字符串的最后一个字符,而不是字符,因此您正在寻找一种方法来检测它是否是单个字符\n
(newline
也称为 ASCII 中的line feed
)。您不想检测字符串是否以两个字符\
(反斜杠)和结尾n
。
这是在相当现代的 Bash 版本中执行此操作的一种方法:
#!/usr/bin/env bash
printf -v x 'hello\n'
[[ "${x: -1:1}" == $'\n' ]] && echo "Ends in newline"
echo done
${x: -1:1}
使用 Bash 的子字符串扩展来返回字符串的最后一个字符。手册页中的语法是${parameter:offset:length}
并指出负偏移量从字符串的末尾而不是开头开始。它还指出,第一个:
和之间需要一个空格,-1
以避免与不同类型的参数扩展混淆。
$'\n'
使用 Bash 的“单引号的特殊变体”语法来表示“ANSI C 标准”指定的字符。
内置printf
命令使用该-v
选项将输出写入指定变量而不是 stdout。此选项可能不适用于所有 shell(并且不适用于外部printf
二进制文件)。 直接printf
支持字符,\n
无需“特殊变体”语法。
正如所写,这仅适用于变量末尾的换行符,但这就是您所要求的。检查字符串中的其他控制字符和/或其他位置将需要不同的语法,具体取决于您的特定需求。
答案2
在任何 POSIX shell 中:
case "$string" in
(*'
') echo The string ends in a newline character;;
(*) echo It does not;;
esac
在包括支持$'...'
ksh93 引用形式(并且将在 POSIX 标准的下一版本中指定sh
)的 bash 的 shell 中,可以使用以下命令更容易阅读:
case "$string" in
(*$'\n') echo The string ends in a newline character;;
(*) echo It does not;;
esac
对于不支持的 shell,其他选项$'...'
是将换行符存储在全局变量中:
NL='
'
或者
eval "$(printf ' NL="\n" CR="\r" TAB="\t" FF="\f" BS="\b" BEL="\a" ')"
为每个控制字符组成一个变量并使用:
case "$string" in
(*"$NL") echo The string ends in a newline character;;
( * ) echo It does not;;
esac
在一些 shell 中(至少是 ksh93、zsh、bash、mksh),您还可以执行以下操作:
if [[ "$string" = *$'\n' ]]; then
echo The string ends in a newline character
else
echo It does not;;
fi
要获取参数的最后一个字符,POSIXly,您可以滥用模式剥离运算符:
if [ "${string#"${string%?}"}" = "$NL" ]; then
echo The string ends in a newline character
else
echo It does not;;
fi
在 zsh 或 yash 中,你可以这样做:
if [ "${string[-1]}" = "$NL" ]; then...
或者简化为zsh
:
if [[ $string[-1] = $'\n' ]]; then...
因为它的数组是稀疏数组,并且$var
是已经的缩写${var[0]}
并且支持多维数组,所以 ksh93 为字符串或数组切片引入了一种尴尬的语法:
if [[ ${string:${#string}-1} = $'\n' ]]; then...
bash(它没有多维数组,但从 ksh 复制了大部分数组设计)在 2.0 中复制了这一点。
在 bash 中,偏移量也可以是负数,从末尾开始计数(甚至是从 4.2 开始的长度)。然而,正如${var:-default}
Bourne shell 中的其他内容一样,算术表达式中后面的第一个字符:
不能是 a -
(nor ),因此您需要or or ...+
${string: -1}
${string:(-1)}
S{string:0-1}
ksh93 在 ksh93m 中复制了这一点,zsh 最终还添加了对${var:offset[:length]}
与 ksh 兼容的支持(尽管由于 zsh 支持 csh 样式而具有更多限制${var:modifiers}
),mksh 也是如此。