I am trying to create a script that look for some files, listed in an input file, all over the computer and then copy those files in a specific folder. So far all ok with a for loop and mdfind "command" | xargs. But the if i add an if statement to create an output file with the list of the files that mdfind didn't find, here comes the problems. Here is my actual code:

if [ $# -eq 0 ]
echo "Please introduce the name of the input file after runnig the command. 
For this script you need an INPUT.txt file containing only the list of the 
samples you want to copy." 
for i in $(cat $1); 
do mdfind "kMDItemDisplayName == $i*.ab1" | xargs -I '{}' cp '{}' 
if [ $? -eq 0 ] 
echo $i >> extractions_not_found.txt
echo $i >> extractions_found.txt

I am using $? to redirect the output of

 mdfind "kMDItemDisplayName == $i*.ab1" | xargs -I '{}' cp '{}' /Users/xxxxx/xxxxx/xxxxx/xxxxxxx/test_moving/;

but it is alway = 0, even when it cant find the one file listed in the input file.

Anyone can help me understand where is the error??

Thank you!

  • This is because $? is getting the exit code of xargs, not of cp or mdfind. – DopeGhoti Jan 23 '18 at 18:25

After you run mdfind ... | xargs cp ..., the error code in $? is that of xargs, since it's the last command in the pipeline. xargs returns 123 if any command it executed failed, but if mdfind doesn't produce any output, then xargs doesn't do anything, so it also doesn't fail.

However, in Bash, you can find the exit codes of all commands in the last pipeline in the array variable PIPESTATUS. The exit code of the first command is ${PIPESTATUS[0]} etc.

$ false | true | xargs false
$ echo "${PIPESTATUS[*]}"
1 0 123

So, instead of using $?, which gives you the exit status of xargs, you could use ${PIPESTATUS[0]} giving you the exit status of mdfind. Or save the lot to another variable and test both. (saved=("${PIPESTATUS[@]}"))

Alternatively, use set -o pipefail so that $? gives you the exit code of last failing command of the pipeline, if any of them fail. (false | true would result in $?=1.)

  • You can also set -o pipefail and set -e. – DopeGhoti Jan 23 '18 at 20:47
  • @DopeGhoti, ah pipefail of course, thanks. set -e only helps here with pipefail, but I don't think they want that at all. – ilkkachu Jan 23 '18 at 20:51
  • so i did the echo ${PIPESTATUS[@]} and this is how it looks like: 0 0 0 0 0 0 0 0 0 0 so basically is always 0 even if is not copying any file because mdfind didn't found (in my case i have an input file with 5 files to look for and the last file doesn't exist on my computer so cant be find and/or copied) – WalterC85 Jan 23 '18 at 22:15

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.