2

I have a project that has a lot of directories which contain files with extension .strings.

These files are localizations in several languages.

For example, I may have 3 files with the same name, like MyView.strings but each file is inside a localization directory like en.lproj, it.lproj or pt-PT.lproj. There are hundreds of these directories inside the project structure.

I am creating a bash script to list the directories where all these files are, by language.

Example: I would like to scan the directory structure and find all en.lproj directories the structure may have and list the full path of all files inside these directories.

For that matter, a command like that will do the trick on the terminal window

find . -type d -name "en.lproj" -print  

but how do I store the result of such a command to an array that I can enumerate later, inside a bash script?

I have tried this

result=($(find . -type d -name "en.lproj" -print))

but because the paths contain spaces, the array is broken on that spaces, and I was expecting result to be an array where each line is a path, containing or not spaces.

I am on macOS BigSur.

4

To store the output of a command as an array, you need:

array=( $(command) )

However, the shell will split the results of the command on the value of $IFS. Since this is usually set to space, tab and newlines, this means that if the command you use returns file names with any of those characters in the name, then the array will have a separate element for each part of the name. To illustrate:

$ touch 'a file with spaces'
$ ls
'a file with spaces'

$ array=( $( find . -type f) )

$ for f in "${array[@]}"; do echo "FF: $f"; done
FF: ./a
FF: file
FF: with
FF: spaces

In your case, if all of your files have simple names with no whitespace, you can just do (no need for -print, that's the default action):

files=( $(find . -type d -name "en.lproj") )

But, to be on the safe side, you can redefine $IFS for this command to ensure that things work for any file name (expect those containing newline characters):

$ IFS=$'\n' array=( $( find . -type f) )
$ for f in "${array[@]}"; do echo "FF: $f"; done
FF: ./a file with spaces

If you need to be able to handle arbitrary file names, including those with newlines, you can use mapfile and set the delimiter to null, and also use the (non-portable, but supported by GNU and BSD find, so it should work on your mac) option -print0 of find to print the results with a null separator instead of a newline:

mapfile -d '' array < <(find . -type f -print0)

This will handle any type of file:

$ touch 'a bad
file'
$ ls
'a bad'$'\n''file'  'a file with spaces'

$ mapfile -d '' array < <(find . -type f -print0)
$ for f in "${array[@]}"; do echo "FF: $f"; done
FF: ./a file with spaces
FF: ./a bad
file
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.