I have a variable x
with trailing newline.
printf -v x 'hello\n'
How to find out if the last character of x
is \n
?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityYou describe the last character of the string, not characters, so you're looking for a way to detect if it's the single-character \n
(aka newline
or, in ASCII, line feed
). You are not looking to detect if the string ends in the two characters \
(backslash) and n
.
Here's one way to do this in fairly modern versions of Bash:
#!/usr/bin/env bash
printf -v x 'hello\n'
[[ "${x: -1:1}" == $'\n' ]] && echo "Ends in newline"
echo done
${x: -1:1}
uses Bash's substring expansion to return the last character of the string. The syntax in the man page is ${parameter:offset:length}
and notes that a negative offset starts from the end of the string rather than the start. It also notes that a space is needed between the first :
and -1
to avoid confusion with a different type of parameter expansion.
$'\n'
uses Bash's "special variant of single quotes" syntax to represent characters as specified by "the ANSI C standard."
The built-in printf
command uses the -v
option to write the output into the specified variable rather than to stdout. This option may not be available in all shells (and isn't available in an external printf
binary). printf
supports characters like \n
directly without the "special variant" syntax.
As written, this will only work for newline at the end of a variable, but that's what you asked for. Checking for other control characters and/or other locations in the string will need different syntax that depends on your particular needs.
In any POSIX shell:
case "$string" in
(*'
') echo The string ends in a newline character;;
(*) echo It does not;;
esac
In shells including bash that support the $'...'
form of quote from ksh93 (and that will be specified for sh
in the next version of the POSIX standard), that can be made easier to read with:
case "$string" in
(*$'\n') echo The string ends in a newline character;;
(*) echo It does not;;
esac
Other option for shells that don't support $'...'
is to store the newline in a global variable:
NL='
'
or
eval "$(printf ' NL="\n" CR="\r" TAB="\t" FF="\f" BS="\b" BEL="\a" ')"
to make up a variable for each of those control characters and use:
case "$string" in
(*"$NL") echo The string ends in a newline character;;
( * ) echo It does not;;
esac
In a few shells (ksh93, zsh, bash, mksh at least), you can also do:
if [[ "$string" = *$'\n' ]]; then
echo The string ends in a newline character
else
echo It does not;;
fi
To get the last character of a parameter, POSIXly, you can abuse the pattern stripping operators:
if [ "${string#"${string%?}"}" = "$NL" ]; then
echo The string ends in a newline character
else
echo It does not;;
fi
In zsh, or yash, you'd do:
if [ "${string[-1]}" = "$NL" ]; then...
Or simplified in zsh
:
if [[ $string[-1] = $'\n' ]]; then...
Because its arrays are sparse arrays, and that $var
is short for ${var[0]}
already and it supports multi-dimensional arrays, ksh93 introduced an awkward syntax for string or array slicing instead:
if [[ ${string:${#string}-1} = $'\n' ]]; then...
bash (which doesn't have multi-dimensional arrays but otherwise copied most of its array design from ksh) copied that in 2.0.
In bash, the offset can also be negative to count from the end (even the length now since 4.2). However as ${var:-default}
is already something else from the Bourne shell, the first character after the :
cannot be a -
(nor +
) in the arithmetic expression, so you need ${string: -1}
or ${string:(-1)}
or S{string:0-1}
...
ksh93 copied that back in ksh93m, zsh also eventually added support for those ${var:offset[:length]}
for compatibility with ksh (though with even more limitations as zsh supports the csh-style ${var:modifiers}
), so did mksh.
-n
flag.echo
there.x='hello\n'
I need a variable with a trailing newline