Home > Back-end >  Store multiline output on bash array
Store multiline output on bash array

Time:03-15

I am trying to store the output of this:

mdfind "kMDItemContentType == 'com.apple.application-bundle'" 

Output is like this:

/Applications/Safari.app
/Applications/Xcode.app
/Applications/Xcode.app/Contents/Applications/Accessibility Inspector.app
/Applications/Xcode.app/Contents/Applications/RealityComposer.app
/Applications/Xcode.app/Contents/Applications/FileMerge.app
/Applications/Xcode.app/Contents/Applications/Instruments.app
/Applications/Xcode.app/Contents/Applications/Create ML.app

I try to store it as an array but the contents are split per spaces:

bash-5.1$ arr=( $(/usr/bin/mdfind "kMDItemContentType == 'com.apple.application-bundle'") )
bash-5.1$ echo ${arr[2]}
/Applications/Xcode.app/Contents/Applications/Accessibility
bash-5.1$ echo ${arr[3]}
Inspector.app
bash-5.1$ 

So how can I do the trick?

CodePudding user response:

Use readarray and process substitution to read a null-delimited series of paths into an array.

readarray -d '' arr < <(mdfind -0 "...")

The -0 option tells mdfind to terminate each path with a null byte instead of a linefeed. (This guards agains rare, but legal, path names that include linefeeds. Null bytes are not a valid character for any path component.)

The -d '' option tells readarray to treat the null byte as the end of a "line".

readarray populates an array with one "line" of input per element. The input is the output of mdfind; the process substitution ensures that readarray executes in the current shell, not a subshell induced by a pipe like

mdfind -0 "..." | readarray -d '' arr

(Under some situations, you can make the last job of a pipeline execute in the current shell; that's beyond the scope of this answer, though.)


Example:

# Using printf to simulate mdfind -0
$ readarray -d '' arr < <(printf 'foo\nbar\000baz\000')
$ declare -p arr
declare -a arr=([0]=$'foo\nbar' [1]="baz")
  •  Tags:  
  • bash
  • Related