LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Slackware (https://www.linuxquestions.org/questions/slackware-14/)
-   -   Bash problem with local IFS variable being ignored under Slackware Current (https://www.linuxquestions.org/questions/slackware-14/bash-problem-with-local-ifs-variable-being-ignored-under-slackware-current-4175645180/)

luvr 12-29-2018 02:50 PM

Bash problem with local IFS variable being ignored under Slackware Current
 
In Bash, I set up an array of strings, e.g.:
Code:

declare -a X=( a b c d )
I then call a function that needs to copy the array values into a string, with the vertical bar as the separator. Under Slackware 14.2, the following script demonstrates what I'm attempting to do:
Code:

#!/bin/bash

function test_internal_field_separator()
{
  local IFS='|'
  local STRING_OF_ARGUMENTS="${@}"

  echo "${STRING_OF_ARGUMENTS}"
}

declare -a X=( a b c d )

test_internal_field_separator "${X[@]}"

The “echo” command within the “test_internal_field_separator” function will produce the following output:
Code:

a|b|c|d
Under Slackware Current, however, the local IFS variable value appears to be ignored, and the array values are separated by spaces instead:
Code:

a b c d
I have no idea which behaviour should be considered right, but I find it highly unlikely that they are supposed to be different.

In any case, once I diagnosed the problem, I modified my code as follows in order to work around it:
Code:

#!/bin/bash

function test_internal_field_separator()
{
  local STRING_OF_ARGUMENTS="${@}"

  STRING_OF_ARGUMENTS="${STRING_OF_ARGUMENTS// /|}"
  echo "${STRING_OF_ARGUMENTS}"
}

declare -a X=( a b c d )

test_internal_field_separator "${X[@]}"

Hence, the issue is no longer particularly critical, even though it violates the POLA (“Principle Of Least Astonishment”) and as such, it likely deserves at least a closer look. :confused:

Just for completeness, I ran the following commands to obtain the kernel and bash versions of both systems:
Code:

cat '/etc/slackware-version'
uname -srv
bash --version

Under Slackware 14.2, I get:
Code:

Slackware 14.2
Linux 4.4.157 #2 SMP Fri Sep 21 00:36:59 CDT 2018
GNU bash, version 4.3.48(1)-release (x86_64-slackware-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Under Slackware Current, the output is as follows:
Code:

Slackware 14.2+
Linux 4.19.12 #1 SMP Fri Dec 21 21:11:12 CST 2018
GNU bash, version 4.4.23(1)-release (x86_64-slackware-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


cowpoke 12-29-2018 03:58 PM

Is it possible your sample is affected by this patch from 4.4.12?

http://ftp.gnu.org/gnu/bash/bash-4.4-patches/bash44-012

Markus Wiesner 12-29-2018 06:39 PM

Using
Code:

  local IFS='|'
  local STRING_OF_ARGUMENTS="${*}"

(* instead of @) works here with bash 4.4.23(1).

According to man bash only "${*}" uses IFS for concatenation:

Code:

  Special Parameters
      The shell treats several parameters specially.  These parameters may only be referenced; assignment to
      them is not allowed.
      *      Expands to the positional parameters, starting from one.  When the expansion is not within dou‐
              ble quotes, each positional parameter expands to a separate word.  In contexts where it is per‐
              formed, those words are subject to further word splitting and  pathname  expansion.  When  the
              expansion  occurs  within  double  quotes,  it  expands to a single word with the value of each
              parameter separated by the first character of the IFS  special  variable.  That  is,  "$*"  is
              equivalent to "$1c$2c...", where c is the first character of the value of the IFS variable.  If
              IFS is unset, the parameters are separated by spaces.  If  IFS  is  null,  the  parameters  are
              joined without intervening separators.
      @      Expands to the positional parameters, starting from one.  When the expansion occurs within dou‐
              ble quotes, each parameter expands to a separate word.  That is, "$@"  is  equivalent  to  "$1"
              "$2"  ...  If  the  double-quoted  expansion  occurs within a word, the expansion of the first
              parameter is joined with the beginning part of the original word, and the expansion of the last
              parameter  is  joined  with  the  last part of the original word.  When there are no positional
              parameters, "$@" and $@ expand to nothing (i.e., they are removed).

So the old behaviour was maybe a bug that has been fixed in 4.4?

luvr 12-30-2018 07:32 AM

Quote:

Originally Posted by Markus Wiesner (Post 5942651)
According to man bash only "${*}" uses IFS for concatenation

Wow... Thanks a lot! I had totally forgotten about the use of “*” as opposed to “@” as an array subscript. Back when I began to take bash arrays seriously, and learned about the differences in behaviour between the two, I needed only the latter, and I have never felt the need to use the former—until now.
Quote:

So the old behaviour was maybe a bug that has been fixed in 4.4?
Sure looks like it, doesn’t it?


All times are GMT -5. The time now is 10:00 AM.