3

My aim is to find $files on some $devices and save them to one or more folders which are namend corresponding to a timestamp of each file. To get the timestamp I wanted to use stat.

In contrast to echo "$files", stat doesn't process each file separately. Instead it seems to process all files at once when I use "".

Do you have any suggestions on how to improve quoting or any other hints on how to make stat able to do what i want it to do? Thank you very much for your help.

#!/bin/bash
for devices in "$(ls /media/*/)";
  do
    for files in "$(find /media/*/$devices -iname *.jpg)";
      do
        echo "$files"   # prints all files in separate lines
        stat "$files"   # seems to process all files at once
        stat $files     # splits file paths at spaces
      done
  done
ha2k
  • 33

2 Answers2

2

The problem is not with stat but with the source data in your for loop; because you have enclosed it all in quotes it becomes one long single entity.

To fix this, remove the quotes around it, thus:

for files in $(find /media/*/$devices -iname "*.jpg");

It works provided that none of the files or paths have spaces. But there is a more elegant solution which works with spaces and even with weird filenames (for instance ones that include quotes or newlines):

while IFS= read -r -d '' file; do
    # operations on each "$file" here
done < <(find /media/*/$devices -type f -iname *.jpg -print0)
gogoud
  • 2,672
  • re alternate suggestion: that's because this uses $file not $files, which is really better since each $file is an individual file. I'm revising my initial suggestion, but the alternate is better really. – gogoud Mar 21 '15 at 11:44
  • Your alternate suggestion works for me (filenames with spaces) very well, thank you! – ha2k Mar 21 '15 at 11:47
1

Don't parse the output of ls. You can't distinguish a newline introduced by ls from a newline in a file name. The same goes for find.

for devices in $(ls /media/*/) is just a complex, broken way of writing for devices in /media/*/*. Instead of for files in $(find …); do …; done, use find … -exec ….

You don't need the two loops here, since you're only enumerating files in order to use the full set later. Your script is simply

find /media/*/* -iname '*.jpg' -exec stat {} +

For more information, see Why does my shell script choke on whitespace or other special characters?