0

In a bash shell, I want to convert an array variable $a into a string of tab separated values. I found a very complete answer by F.Hauri, using IFS, but then I could not make it work in a script. The reason seems to be that using the IFS variable behaves differently in scripts and terminals.

Here is an example (for ease of read, I am using IFS='*' instead of IFS=$'\n'):

a=("0.0 mm" "0.1 mm" "0.3 mm" "0.2 mm")
IFS='*';echo "${a[*]// /'|'}";IFS=$' \t\n';

When I type it directly a bash terminal, I get this output :

0.0|mm*0.1|mm*0.3|mm*0.2|mm

But running the same from a script, yields:

0.0*mm*0.1*mm*0.3*mm*0.2*mm

As you can see, the '*' character is used as separator everywhere when I run this command from a script.

Please help me understand why that happens and how to fix it. Thank you.

(I am running this in Ubuntu 22.04.3 LTS, installed under windows using wls.)

3
  • 2
    Regarding "The reason seems to be that using the IFS variable behaves differently in scripts and terminals." - no, whatever problem you're having, that is not it. Show a complete, minimal script that has the problem so we can reproduce it. You say you want to output tab-separated values but then your example shows output with |-separated values- please edit your question to be consistent between your requirements and example. Commented Feb 28, 2024 at 12:42
  • 2
    There are only a few reasons things behave differently in a terminal than from a non-interactive shell. First thing to check is that you are using the same shell in the same mode. If your interactive shell is bash and the shebang in your script is /bin/sh, try changing the shebang to /bin/bash. That will solve this type of issue 95% of the time. (But a better solution is to stop using bashisms) Commented Feb 28, 2024 at 13:03
  • The use of IFS in the code is not safe. It's worse than the problem described in Bash Pitfalls #49 (OIFS="$IFS"; ...; IFS="$OIFS"). There are a few good ways to do what you are trying to do. The accepted answer to How can I convert an array into a comma separated string? has a few of them. Commented Feb 28, 2024 at 13:53

2 Answers 2

2

Don't mess with IFS, use printf instead:

a=("0.0 mm" "0.1 mm" "0.3 mm" "0.2 mm")
printf '%s\t' "${a[@]}"
0.0 mm  0.1 mm  0.3 mm  0.2 mm

Printf can create vars:

printf -v var '%s\t' "${a[@]}"
echo "$var"
0.0 mm  0.1 mm  0.3 mm  0.2 mm
Sign up to request clarification or add additional context in comments.

2 Comments

That would add a tab to the end of $var, try piping it to cat -A or similar so see control chars.
Yes, so you'd have to do echo "${var%$'\t'}"
2

It behaves the same way inside or outside of a script:

Outside:

$ a=("0.0 mm" "0.1 mm" "0.3 mm" "0.2 mm")
$ IFS='*';echo "${a[*]// /'|'}";IFS=$' \t\n';
0.0|mm*0.1|mm*0.3|mm*0.2|mm

Inside:

$ cat tst.sh
#!/usr/bin/env bash

a=("0.0 mm" "0.1 mm" "0.3 mm" "0.2 mm")
IFS='*';echo "${a[*]// /'|'}";IFS=$' \t\n';

$ ./tst.sh
0.0|mm*0.1|mm*0.3|mm*0.2|mm

If, as you say at the start of your question, you want to:

convert an array variable $a into a string of tab separated values

then all you need is:

$ a=("0.0 mm" "0.1 mm" "0.3 mm" "0.2 mm")
$ var=$( IFS=$'\t'; echo "${a[*]}" )

$ echo "$var"
0.0 mm  0.1 mm  0.3 mm  0.2 mm

$ echo "$var" | cat -A
0.0 mm^I0.1 mm^I0.3 mm^I0.2 mm$

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.