Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.debian.user > #176429 > unrolled thread
| Started by | "foo fighter" <lopiuh@gmx.net> |
|---|---|
| First post | 2017-01-07 22:00 +0100 |
| Last post | 2017-01-10 14:40 +0100 |
| Articles | 4 — 2 participants |
Back to article view | Back to linux.debian.user
Bash different behaviour of read / strings in jessie versus stretch (regression?) "foo fighter" <lopiuh@gmx.net> - 2017-01-07 22:00 +0100
Re: Bash different behaviour of read / strings in jessie versus stretch (regression?) Greg Wooledge <wooledg@eeg.ccf.org> - 2017-01-09 15:00 +0100
Aw: Re: Bash different behaviour of read / strings in jessie versus stretch (regression?) "foo fighter" <lopiuh@gmx.net> - 2017-01-10 01:20 +0100
Re: Re: Bash different behaviour of read / strings in jessie versus stretch (regression?) Greg Wooledge <wooledg@eeg.ccf.org> - 2017-01-10 14:40 +0100
| From | "foo fighter" <lopiuh@gmx.net> |
|---|---|
| Date | 2017-01-07 22:00 +0100 |
| Subject | Bash different behaviour of read / strings in jessie versus stretch (regression?) |
| Message-ID | <sX6fL-5fd-9@gated-at.bofh.it> |
Hi,
the same code behaves different in jessie and stretch. Does someone know why, and if this could be a regression?
In jessie "version 1" and "version 2" behave identical. In stretch, "version 2" behaves different (only one item in array)
The code difference between "version 1" and "version 2" lies in quotation marks around $_inputstring
Yours lopiuh
Code:
#!/usr/bin/env bash
set -o errexit # (set -e)
set -o nounset # (set -u)
set -o pipefail #
shopt -s nullglob # enable
#shopt -s failglob
#set -o noglob
clear
echo "===========================Version 1==========================="
echo "Bash Version: $BASH_VERSION"
echo -n "IFS:"; echo "$IFS" | cat -vte
echo
unset _array; declare -a _array
_inputstring="$(echo -e "item01\nitem02\nitem03")"
echo "inputstring:"
echo -n "$_inputstring" | xxd; echo
read -ra _array <<<$(echo $_inputstring) # <<< NO -"- around string
#read -ra _array <<<"$_inputstring" #<--- only one item, even in jessie
#read -ra _array <<<$_inputstring #<--- only one item, even in jessie
echo "itemcount of array: ${#_array[@]}"
for i in "${_array[@]}"; do
echo -n "element: "; echo -n "$i" | xxd; echo
done
#
echo "===========================Version 2==========================="
echo "Bash Version: $BASH_VERSION"
echo -n "IFS:"; echo "$IFS" | cat -vte
echo
unset _array; declare -a _array
_inputstring="$(echo -e "item01\nitem02\nitem03")"
echo "inputstring:"
echo -n "$_inputstring" | xxd; echo
read -ra _array <<<$(echo "$_inputstring") # <<< WITH -"- around string
#read -ra _array <<<"$_inputstring" #<--- only one item, even in jessie
#read -ra _array <<<$_inputstring #<--- only one item, even in jessie
echo "itemcount of array: ${#_array[@]}"
for i in "${_array[@]}"; do
echo -n "element: "; echo -n "$i" | xxd; echo
done
exit
Output of jessie:
===========================Version 1===========================
Bash Version: 4.3.30(1)-release
IFS: ^I$
$
inputstring:
0000000: 6974 656d 3031 0a69 7465 6d30 320a 6974 item01.item02.it
0000010: 656d 3033 em03
itemcount of array: 3
element: 0000000: 6974 656d 3031 item01
element: 0000000: 6974 656d 3032 item02
element: 0000000: 6974 656d 3033 item03
===========================Version 2===========================
Bash Version: 4.3.30(1)-release
IFS: ^I$
$
inputstring:
0000000: 6974 656d 3031 0a69 7465 6d30 320a 6974 item01.item02.it
0000010: 656d 3033 em03
itemcount of array: 3
element: 0000000: 6974 656d 3031 item01
element: 0000000: 6974 656d 3032 item02
element: 0000000: 6974 656d 3033 item03
Output of stretch:
===========================Version 1===========================
Bash Version: 4.4.5(1)-release
IFS: ^I$
$
inputstring:
00000000: 6974 656d 3031 0a69 7465 6d30 320a 6974 item01.item02.it
00000010: 656d 3033 em03
itemcount of array: 3
element: 00000000: 6974 656d 3031 item01
element: 00000000: 6974 656d 3032 item02
element: 00000000: 6974 656d 3033 item03
===========================Version 2===========================
Bash Version: 4.4.5(1)-release
IFS: ^I$
$
inputstring:
00000000: 6974 656d 3031 0a69 7465 6d30 320a 6974 item01.item02.it
00000010: 656d 3033 em03
itemcount of array: 1
element: 00000000: 6974 656d 3031 item01
[toc] | [next] | [standalone]
| From | Greg Wooledge <wooledg@eeg.ccf.org> |
|---|---|
| Date | 2017-01-09 15:00 +0100 |
| Subject | Re: Bash different behaviour of read / strings in jessie versus stretch (regression?) |
| Message-ID | <sXIEq-4UO-15@gated-at.bofh.it> |
| In reply to | #176429 |
On Sat, Jan 07, 2017 at 09:54:34PM +0100, foo fighter wrote: > In jessie "version 1" and "version 2" behave identical. In stretch, "version 2" behaves different (only one item in array) > echo "===========================Version 2===========================" [...] > _inputstring="$(echo -e "item01\nitem02\nitem03")" _inputstring=$'item01\nitem02\nitem03' > read -ra _array <<<$(echo "$_inputstring") # <<< WITH -"- around string This is just wrong. You're using $(echo) which is silly and pointless, and you've failed to quote the result, and you've failed to tell read not to stop reading at the first newline, and you've failed to set IFS to use only newlines as delimiters between array elements. The only way yours "works" at all is because two of your errors are canceling each other. The unquoted $(echo) is doing word splitting and then reassembling the result, effectively replacing each newline with a space, so that you only have a single line of input, which is why read sees the entire input.... Yikes. Really, you should be using mapfile (a.k.a. readarray) when reading a multi-line input where each line is intended to become one array element. _inputstring=$'item01\nitem02\nitem03' mapfile -t _array <<< "$_inputstring" declare -p _array Try that in both versions of bash, and I believe that it will work consistently and correctly. Now I get to start guessing. My first guess is that you are doing something like this: tmp=$(some program that writes multiple lines) read -ra array <<< $(echo "tmp") # wrong Just do this instead: mapfile -t array < <(some program that writes multiple lines)
[toc] | [prev] | [next] | [standalone]
| From | "foo fighter" <lopiuh@gmx.net> |
|---|---|
| Date | 2017-01-10 01:20 +0100 |
| Subject | Aw: Re: Bash different behaviour of read / strings in jessie versus stretch (regression?) |
| Message-ID | <sXSkp-2vm-1@gated-at.bofh.it> |
| In reply to | #176498 |
Hi Greg,
thanks for your answer. I used "read" because it offered different delimiter (IFS) at the same time as far as my elements are seperateed by LF or (one) space (per element). You are right it is stdout of other programs. Furthermore globbing was not intended in this area but I did not want to toggle globbing off/on with "set" within the script. As far as mapfile needs LF as delimiter (as far as I see) I do now a search and replace (space to LF)
mapfile -t _array <<<"${_inputstring// /$'\n'}"
This works in both bash versions.
Thaaaaanks !!
Yours
Lopiuh
[toc] | [prev] | [next] | [standalone]
| From | Greg Wooledge <wooledg@eeg.ccf.org> |
|---|---|
| Date | 2017-01-10 14:40 +0100 |
| Subject | Re: Re: Bash different behaviour of read / strings in jessie versus stretch (regression?) |
| Message-ID | <sY4OC-1Tf-37@gated-at.bofh.it> |
| In reply to | #176522 |
On Tue, Jan 10, 2017 at 01:10:53AM +0100, foo fighter wrote:
> mapfile -t _array <<<"${_inputstring// /$'\n'}"
For larger inputs, this will probably be more efficient:
mapfile -t _array < <(your command | tr ' ' '\n')
Bash's substitution can be rather slow on large strings.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.debian.user
csiph-web