Just set IFS
according to you needs and let the shell perform word splitting:
IFS=':'
for dir in $PATH; do
[ -x "$dir"/"$1" ] && echo $dir
done
This works in bash
, dash
and ksh
, but tested only with the latest versions.
openssl
's stdin is a byte stream.
The contents of $user
is a sequence of non-0 bytes (which may or may not form valid characters in UTF-8 or other character set/encoding).
printf %s "$user"
's stdout is a byte stream.
printf %s "$user" | openssl dgst -sha256 –binary
Will connect printf
's stdout with openssl
's stdin. openssl
's stdout is another byte stream.
Now, if you're inputing $user
from the user from a terminal, The user will enter it by pressing keys on his keyboard. The terminal will send corresponding characters (as written on the key label) encoded in its configured character set. Usually, that character set will be based on the character set in the current locale. You can find what that is with locale charmap
.
For instance, with a locale like fr_FR.iso885915@euro
, and an xterm
started in that locale, locale charmap
will return ISO-8859-15
. If the user enters stéphane
as the username, that é
will likely be encoded as the 0xe9
byte because that's how it's defined in the ISO-8859-15
character set.
If you want that é
to be encoded as UTF-8 before passing to openssl
, that's where you'd use iconv
to convert that 0xe9
byte to the corresponding encoding in UTF-8 (two bytes: 0xc3
0xa9
):
IFS= read -r user # read username from stdin as a sequence of bytes
# assumed to be encoded from characters as per the
# locale's encoding
printf %s "$user" |
iconv -t utf-8 | # convert from locale encoding to UTF-8
openssl dgst -sha256 –binary
Best Answer
Bourne/POSIX-like shells have a split+glob operator and it's invoked every time you leave a parameter expansion (
$var
,$-
...), command substitution ($(...)
), or arithmetic expansion ($((...))
) unquoted in list context.Actually, you invoked it by mistake when you did
for name in ${array[@]}
instead offor name in "${array[@]}"
. (Actually, you should beware that invoking that operator like that by mistake is source of many bugs and security vulnerabilities).That operator is configured with the
$IFS
special parameter (to tell what characters to split on (though beware that space, tab and newline receive a special treatment there)) and the-f
option to disable (set -f
) or enable (set +f
) theglob
part.Also note that while the
S
in$IFS
was originally (in the Bourne shell where$IFS
comes from) for Separator, in POSIX shells, the characters in$IFS
should rather be seen as delimiters or terminators (see below for an example).So to split on
_
:To see the distinction between separator and delimiter, try on:
That will split it into
var1
andvar2
only (no extra empty element).So, to make it similar to JavaScript's
split()
, you'd need an extra step:(note that it would split an empty
$string
into 1 (not 0) element, like JavaScript'ssplit()
).To see the special treatments tab, space and newline receive, compare:
(where you get
var1
andvar2
) withwhere you get:
''
,var1
,''
,var2
,''
.Note that the
zsh
shell doesn't invoke that split+glob operator implicitly like that unless insh
orksh
emulation. There, you have to invoke it explicitely.$=string
for the split part,$~string
for the glob part ($=~string
for both), and it also has a split operator where you can specify the separator:or to preserve the empty elements:
Note that there
s
is for splitting, not delimiting (also with$IFS
, a known POSIX non-conformance ofzsh
). It's different from JavaScript'ssplit()
in that an empty string is split into 0 (not 1) element.A notable difference with
$IFS
-splitting is that${(s:abc:)string}
splits on theabc
string, while withIFS=abc
, that would split ona
,b
orc
.With
zsh
andksh93
, the special treatment that space, tab or newline receive can be removed by doubling them in$IFS
.As a historic note, the Bourne shell (the ancestor or modern POSIX shells) always stripped the empty elements. It also had a number of bugs related to splitting and expansion of $@ with non-default values of
$IFS
. For instanceIFS=_; set -f; set -- $@
would not be equivalent toIFS=_; set -f; set -- $1 $2 $3...
.Splitting on regexps
Now for something closer to JavaScript's
split()
that can split on regular expressions, you'd need to rely on external utilities.In the POSIX tool-chest,
awk
has asplit
operator that can split on extended regular expressions (those are more or less a subset of the Perl-like regular expressions supported by JavaScript).The
zsh
shell has builtin support for Perl-compatible regular expressions (in itszsh/pcre
module), but using it to split a string, though possible is relatively cumbersome.