7

I am looking to automate my xcode projects. It all works fine except the projects name with spaces. I have tried the following commands:

output_apps=`find ./ -name "*.app" -print`
output_apps=`find ./ -name "*.app"`

When I run

find ./ -name "*.app" -print 

without storing into variable, it gives me output as expected as mentioned below:

.//Ten EU.app
.//Ten Official App EU.app
.//Ten Official App.app
.//Ten.app

However when I store the output of above command in a variable as below

output_apps=`find ./ -name "*.app" -print`

and then run the following for loop for get the names

for curr_app in $o
do 
    echo "$curr_app"
done

It shows

.//Ten
EU.app
.//Ten
Official
App
EU.app
.//Ten
Official
App.app
.//Ten.app

How do I maintain the spaces between each output and get the following output?

Ten EU.app
Ten Official App EU.app
Ten Official App.app
Ten.app
Vebz
  • 177
  • 1
  • 1
  • 8
  • 1
    There are couple of solutions [here](http://www.linuxquestions.org/questions/linux-newbie-8/how-to-loop-over-text-file-lines-within-bash-script-for-loop-522355/)... One with `while` loop and `read` is really noteworthy. – plesiv Jan 09 '13 at 23:09
  • the while loop worked when the names are extracted from the filename. However, I am extracting the required files after pipe redirection from xcodebuild command. Is there a way to put find as input in the while loop? – Vebz Jan 09 '13 at 23:25

2 Answers2

17

If you don't need to store the file names in a variable, you can use find -print0 in combination with xargs -0. This separates the found entries by NUL bytes instead of newlines. xargs reads these NUL separated values and calls some command with as many arguments as possible.

find ./ -name "*.app" -print0 | xargs -0 some-command

If you want, you can limit the number of arguments given to some-command with xargs -n 1

find ./ -name "*.app" -print0 | xargs -0 -n 1 some-command

Yet another approach is to read the files with a while loop

find ./ -name "*.app" -print | while read f; do
    some-command "$f"
done

This calls some command with one file at a time. The important point is to enclose the $f into double quotes.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
  • Thanks @Olaf. The first two queries brings result `.//Ten EU.app .//Tenn Official App EU.app .//Ten Official App.app .//Ten.app`. I will try to put them in an array as suggested by ormaaj. If that fails, I will just create a temp file, put values and read it from there as suggested by zplesivcak. There is a lot more code and this small part has taken forever. – Vebz Jan 10 '13 at 09:27
  • How to put them in array? – optimus prime Mar 25 '16 at 14:07
  • @vvn One way would be to use the while loop and add the values one by one. See also question http://stackoverflow.com/q/1951506/1741542 – Olaf Dietsche Mar 25 '16 at 22:07
1

The file names may contain spaces. You need to ask find to separate them via NULL(\0). Use find -print0.

alinsoar
  • 15,386
  • 4
  • 57
  • 74
  • 3
    No force in the known universe can put a NUL byte into a bash variable. – ormaaj Jan 09 '13 at 23:06
  • I am sorry, I couldn't interpret your answer into complete command. I tried output=`find ./ -name "*.app" -print0`. How do I adjust NULL(\0) – Vebz Jan 09 '13 at 23:28
  • @Vebz It isn't a complete answer. First you need the nonstandard (but common) `-print0` feature (it's a good thing). Then you need a way to read NUL-delimited streams (Harder. Also generally not possible without non-standard extras. Have a look at Bash's `read -d`). If you need to store the results, you'll want to use an array. – ormaaj Jan 09 '13 at 23:49
  • A complete example would be `for i in $(find -print0 | xargs -0 echo); do echo $i; done` – alinsoar Jan 10 '13 at 01:17
  • @alinsoar your method brings the same result as mine. (Even when I add double quotes to "$i". – Vebz Jan 10 '13 at 09:16
  • @ormaaj I will give it a try and post my answer if I get success. Thanks – Vebz Jan 10 '13 at 09:17