简体   繁体   中英

Bash loop command on list

I am on OS X using bash and wanting to read the data in a key embedded in every Application in the Applications directory. The result seems to be the 'defaults' command trying to apply itself to the whole list instead of each returned Application.

#!/bin/bash

# appList=$(ls /Applications)

for APPS in "$( ls /Applications )" ; do
        result=$(defaults read /Applications/"$APPS"/Contents/Info DTPlatformBuild)
done

echo result is $result

exit 0

Any help appreciated.

Putting quotes around something like "$( ls /Applications )" causes the shell to treat the quoted thing as a single argument rather than breaking it at spaces into multiple arguments. So your for loop will only be done once, with APPS set to the entire list of applications, rather than running once for each application. If you remove the quotes, it will run once for each application, as long as the applications don't have any spaces in their names. Unfortunately if there are spaces in the names, it will break the name at the spaces and not work properly.

Dealing safely with filenames with spaces in them is a pain in the shell, which is why it is recommended that you never use spaces in filenames. Unfortunately Microsoft and Apple don't follow that advice. One thing you could do in this case is something like:

ls /Applications | while read APPS; do
    result=...whatever
done

Another issue with your script (as written) is that it will store into result in each iteration, overwriting the previous result. So the contents of $result at the end that you are printing will be just the result of the last iteration.

I would suggest no to use ls command for looping because its error prone. Run your loop like this to find Application recursively:

find /Applications -name "*.app" -print0 | while IFS= read -r -d '' APP
do
    defaults read "$APP/Contents/Info" DTPlatformBuild
done

Since all you are interested in echoing the result there is no need to store defaults command's output in a variable and then echo it.

I am going to go with the below. The text file "appleApps.txt" is simply a listing of the default Apple Applications on a new build to abstain from the search. A valid company application will have a new key inserted into the "Info.plist" file with a boolean set to true .
Thus we now have a mechanism to report on whether user's are installing their own copies of Applications we already package ourselves.

#!/bin/bash
echo " "
echo " "
rm -f /tmp/validApps /tmp/notValid
find /Applications -name "*.app" | grep -v -F -f /Library/Application\ Support/CompanyData/appleApps.txt | while read APP
do
appVersion=`defaults read "$APP/Contents/Info" Company 2>/dev/null`
if test "$appVersion" = 1 ; then
    echo "$APP : $appVersion" >> /tmp/validApps
else
    echo "$APP" >> /tmp/notValid
fi
done

echo " "
echo " "

result=$(cat -n /tmp/validApps)
notValidResult=$(cat -n /tmp/notValid)

printf "%s\n" "Our packaged Applications are:" "$result"
echo " "
echo " "
printf "%s\n" "User installed Applications are:" "$notValidResult"
echo " "

rm -f /tmp/validApps /tmp/notValid

exit 0

Thanks for the tips as far as my errors with $result

I read up on why not to us ls and have learnt not to do it, as prompted by both @chris and @anubhava

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM