Bash: set IFS to Space after specific character only?

2.4k views Asked by At

I'm using IFS=', ' to split a string of comma-delimited text into an array. The problem is that occasionally one of the comma-delimited items contains a space following a :. The resulting array contains that item as two separate array elements. Is it possible to set IFS to only split ', ' and ignore a comma-delimited item that contains ': ' (or any other character for that matter)?

See the comma-delimited string returned from the first command below, note the second item has the :. See the MarkerNames[1] and MarkerNames[2] to see the unwanted split in the second command below.

$ exiftool -s3 -TracksMarkersName audioFile.wav
Marker1, Tempo: 120.0, Silence, Marker2, Silence.1, Marker3, Silence.2, Marker4, Silence.3, Marker5

$ IFS=', ' read -r -a MarkerNames <<< $(exiftool -s3 -TracksMarkersName audioFile.wav)
$ declare -p MarkerNames
declare -a MarkerNames='([0]="Marker1" [1]="Tempo:" [2]="120.0" [3]="Silence" [4]="Marker2" [5]="Silence.1" [6]="Marker3" [7]="Silence.2" [8]="Marker4" [9]="Silence.3" [10]="Marker5")'
2

There are 2 answers

2
tripleee On BEST ANSWER

IFS contains an enumeration of the characters which each can be a field separator. So ", " says "any run of spaces or commas separates my fields".

The simplest workaround I think would be to preprocess the output so you get the breaks where you want them.

IFS='~' MarkerNames=($(exiftool -s3 -TracksMarkersName audioFile.wav | sed 's/, /~/g'))

This of course requires you to find another IFS value which doesn't occur in your data. If Bash 4+ is available, maybe use a newline and readarray.

0
Renaud Pacalet On

You could split on commas and remove the leading / trailing spaces afterwards:

IFS=',' read -r -a MarkerNames <<< $(exiftool -s3 -TracksMarkersName audioFile.wav)
shopt -s extglob                          # Needed for extended glob
MarkerNames=( "${MarkerNames[@]/#*( )}" ) # Remove leading spaces
MarkerNames=( "${MarkerNames[@]/%*( )}" ) # Remove trailing spaces