plistbuddy - 如何拦截错误(密钥不存在)

10 error-handling bash

我正在阅读一个plist文件,使用plistbuddy; 我正在收集不同词典的数据.

问题在于,由于某种原因,有时值不存在,所以我得到了输出"Key does not exist".

有没有办法拦截这个,所以,如果该值不存在,我可以用0或其他值替换它?

我用shell脚本; 我正在考虑使用一个简单的if ... else语句,试图检查字符串"key does not exist",但它不起作用(我从来没有达到true条件,我认为消息只是stdout,而不是保存在我的变量中).

文档没有多大帮助,所以我卡住了.

由于我计算了平均值,因此错误会影响我的计算,这就是为什么我要添加0,所以我可以稍后检查是否有0并更改函数以相应地计算平均值.

基本上这是我的代码的一个例子:(filename是plist文件名)

for i in {0..3}
do
    TempValue=$(/usr/libexec/PlistBuddy -c "print :process:$i:testname:result" $fileName)
    echo $TempValue
    Data_results+=($TempValue)
done 

# Calculate Average
tmpResult=`echo ${Data_results[0]} + ${Data_results[1]} + ${Data_results[2]} + ${Data_results[3]}|bc`
AverageTime=$(bc <<< "scale=10; $tmpResult / 4")  
echo "average for test name: " $AverageValue
Run Code Online (Sandbox Code Playgroud)

谢谢!

mkl*_*nt0 12

OS X的/usr/libexec/PlistBuddy实用程序是一个表现良好的CLI:

  • 如果成功,它的退出代码是 0
  • 如果失败,其退出代码为非零
  • 它的常规输出被发送到stdout,错误消息被发送到stderr

检查成功有多种方法; 例如:

# Query and save the value; suppress any error message, if key not found.
val=$(/usr/libexec/PlistBuddy -c 'print ":SomeKey"' file 2>/dev/null)

# Save the exit code, which indicates success v. failure
exitCode=$? 

if (( exitCode == 0 )) then # OK
   # handle success ....
else
   # handle failure ...
fi
Run Code Online (Sandbox Code Playgroud)

更新1

这是您的特定用例的片段; 您可以按原样运行它以查看它是如何工作的(它使用Finder存储其首选项的Plist文件):

# Loop over keys and retrieve the corresponding values.
# If the key doesn't exist, assign '0'.
for key in ':AppleShowAllFiles' ':NoSuchKey'; do
    val=$(/usr/libexec/PlistBuddy -c "print \"$key\"" \
          ~/Library/Preferences/com.apple.finder.plist 2>/dev/null || printf '0')
    echo "Value retrieved: [$val]"
done
Run Code Online (Sandbox Code Playgroud)

如您所见,$val将包含0第二个不存在的键的情况.

所述2>/dev/null禁止显示stderr输出(错误消息),并且||操作者被用来提供一种替代的命令的情况下,以创建输出调用的PlistBuddy指示失败(经由它的退出代码).

唯一需要注意的是,您将无法区分不存在的密钥和更基本的故障,例如不存在或损坏的Plist文件.处理更复杂,因为PlistBuddy不使用不同的退出代码来区分这些情况.


更新2

这是一个简化的代码版本,包含所需的默认为0的逻辑:

# Collect temperatures.
Data_results=()
for i in {0..3}
do
    Data_results+=( $(/usr/libexec/PlistBuddy \
            -c "print :process:$i:testname:result" "$fileName" 2>/dev/null || 
            printf '0') )
done 

# Calculate average
AverageValue=$(bc <<< \
                "scale=10; $(( ${Data_results[@]/%/ +} 0 )) / ${#Data_results[@]}")  
echo "average for test name: " $AverageValue
Run Code Online (Sandbox Code Playgroud)

注意:$(( ... ))是一个算术扩展(仅限整数),它使用一个小技巧来总结数组的元素:${Data_results[@]/%/ +}追加+到数组的每个元素.例如,输入数组(1 2 3)将扩展为1 + 2 + 3 +; 因为那留下了悬空+,我只是添加了另一个0来形成一个有效的表达式.结合除以${#Data_results[@]}- 数组中元素的数量 - 该命令然后使用任何大小的数组.