0

I've found a bad habit file naming among the users of the QNAP Linux NAS system I'm administering. We have a Mac OS network, and some folders and files are named using the "/" character that I know it's causing problems to Linux file system. As a matter of fact, from the Mac OS side, the files containing "/" simply disappear, since QTS replaces automatically all instances with "/" with ":".

I'd like to search and rename filenames from ":" to "_".

Discussing on the web I've found that I can SSH connect to the Linux NAS from my Mac with Terminal and perform a script like this:

for f in $(find /share/Public/demofind -name "*:*"); do mv $f ${f/:/_}; done

assuming that the files are in /demofind folder.

I launched the script, but got this error:

    [/share/Public] # for f in $(find /share/Public/demofind/ -name "*:*"); do mv $f ${f/:/_}; done
mv: unable to rename `/share/Public/demofind/Redazionali': No such file or directory
mv: unable to rename `01:03:19.pdf': No such file or directory
mv: unable to rename `/share/Public/demofind/Redazionali': No such file or directory
mv: unable to rename `06:09:19.pdf': No such file or directory
[/share/Public] # for f in $(find /share/Public/demofind/ -name "*:*"); do mv $f ${f/:/_}; done
mv: unable to rename `/share/Public/demofind/Redazionali': No such file or directory
mv: unable to rename `01:03:19.pdf': No such file or directory
mv: unable to rename `/share/Public/demofind/Redazionali': No such file or directory
mv: unable to rename `06:09:19.pdf': No such file or directory

By the way, the files to rename have a syntax like this: "Redazionali 06:09:19.pdf"

The NAS seems to be running BusyBox v1.01 (2021.12.12-04:24+0000) so I would need a solution which is compatible with this platform.

Aserre
  • 4,916
  • 5
  • 33
  • 56
  • macOS doesn't create filenames with `/` in it. The Finder is misleading you (and everyone else) by artificially showing it like that. – Fravadona Jan 17 '22 at 18:03

1 Answers1

1

The immediate problem is that you have broken quoting but your code has other problems too.

The robust solution would be

find /share/Public/demofind -name "*:*" -depth -exec bash -c '
    for f; do mv "$f" "${f//:/_}"; done' _ {} +

Putting the for loop inside find -exec works around pesky problems around file names with unusual characters in them, not just spaces (though your for loop would also inherently break on just single spaces, too; you would have to separately tell the shell to not perform whitespace tokenization if you used the output from find in a command substitution, but again, the proper fix is to simply not do that).

For details, please review https://mywiki.wooledge.org/BashFAQ/020

The -depth option to find says to traverse the directory tree depth-first; this is important when renaming, so that you don't end up renaming directories before you rename the files within them, which then leads to errors when the file you want to rename no longer exists where it was originally found.

The parameter expansion ${f//:/_} is a Bash feature; if you don't have Bash, you have to use an external tool (or a really hairy function around the more pedestrian parameter expansion facilities of POSIX sh; but let's not go there).

find /share/Public/demofind -name "*:*" -depth -exec sh -c '
    for f; do mv "$f" "$(echo "$f" | tr : _)"; done' _ {} +

If your platform doesn't even support find -exec you can manually loop over the output from find but again, see the FAQ link above for a number of caveats.

find /share/Public/demofind -name "*:*" -depth -print |
while IFS='' read -r f; do
    mv "$f" "$(echo "$f" | tr : _)"
done
tripleee
  • 175,061
  • 34
  • 275
  • 318