2

I'm looking for an easy way to rename many files on my Synology NAS. find and sed are available, but not rename.

I can get a list of these files and folders with

find . \( -type d -name "@*" -prune \) -o \( -name "**" \) -print

The above find statement displays all files containing a "/" character, in Synology bash substituted as "".

All the special charactes that I need to replace are:  / \ : ? ' ’ ´ ’ 

Depending on the platform and the file sharing protocol being used these characters will look differently, display differently or not at all or will cause different kind of problems. I can find these characters within Synology bash with: -name "**" -o -name '*\\*' -o -name "*:*" -o -name "*\?*" -o -name "*\'*" -o -name "*´*" -o -name "*`*"

How can I replace these characters in each of the files and directories it finds? I will start with the character "/".

Thanks a lot for any help!

Gary

11
  • The dot in"*.*" is not a printable one, I can't paste it in the terminal, are you sure that is the correct character? Oct 19, 2021 at 10:21
  • Why not use -exec with mv and sed like you suggest yourself? This seems reasonable to me. Just try in a safe folder first before spreading it over the whole file structure. Also, better use mv -i to avoid file loss in case of a problem.
    – Philippos
    Oct 19, 2021 at 10:37
  • By "replace" you mean removing them or replacing for something else? Oct 19, 2021 at 10:40
  • 1
    @schrodigerscatcuriosity if the OP can identify the set of files that match the character, we should assume it represents the right one even if we can't paste it
    – roaima
    Oct 19, 2021 at 10:44
  • @roaima fair enough, I didn't know that you could have characters that can be pasted in the terminal (or google), although with unicode keyboard shortcut I could. Oct 19, 2021 at 11:19

3 Answers 3

2

Assuming that the find command matches the exact set of files you want to rename, and that you want to rename to "safe" filenames. Without knowing the precise character you've got in your filenames I can only offer suggestions, but here are two.

  1. Remove the strange character. This presupposes the character can be handled natively by bash substitutions

     find . -depth \( -type d -name "@*" -prune \) -o \( -name "**" -execdir \
         bash -c 'echo "Processing $PWD"; for f; do echo mv -- "$f" "${f///}"; done' _ {} + \)
    
  2. Keep only known characters. Make sure that tr has the set of characters you want to keep.

     find . -depth \( -type d -name "@*" -prune \) -o \( -name "**" -execdir \
         bash -c 'echo "Processing $PWD"; for f; do echo mv -- "$f" "$(tr -cd '[:alnum:][:punct:][:space:]' <<<"$f")"; done' _ {} + \)
    

In both cases remove echo to convert the debug into an active statement.

4
  • roaima, you're right. The exact list of special characters is: Oct 20, 2021 at 10:15
  • / \ : ? ' ’ ´ ’ ` The difficulty is: Synology replaces some (not all) of them with its own special characters. So, in this bash command, "/" is for example "". Also, depending on the plattform and file sharing protocol the shares are accessed, these characters will display and behave differently and wreaking havoc in a different way. I will edit my question to include this information. Oct 20, 2021 at 10:25
  • @GaryCzychi it sounds like the locale isn't set right on the Synology. I've not seen this problem with QNAPs but I have on a Samba share on a different Linux-based system. Fixing the locale fixed the character set, and no filenames then displayed with strange characters
    – roaima
    Oct 20, 2021 at 10:52
  • 1
    I tried the first one and it works like a charm. I changed it so that it deosn't just deletes the "/", but replaces it with "·" — bash -c 'for f; do mv -- "$f" "${f///·}"; done' _ {} + ) Oct 21, 2021 at 6:29
2

Here's an alternative using a for loop:

# Option globstar activates the ** (search recursivelly).
# Option nullglob removes an * when it matches no file/dir.
$ shopt -s globstar nullglob
$ for i in **/*; do
    # if the name of the file matches the pattern
    # perform the `mv` command
    [[ "$(basename "$i")" =~ ^@.*$ ]] && \
      mv -- "$i" "$(echo "$i" | sed -e 's;^@;;' -e 's;/@;/;')"
    [[ "$(basename "$i")" =~ ^**$ ]] && \
      mv -- "$i" "$(echo "$i" | sed 's;;;')"
  done

Note: before executing moving/removing commands is a good idea to make a backup first.

0

If your find command gives you desired result, you can pipe it to sed, and then from sed to bash (or redirect to file instead pipe to bash/ash):

find . \( -type d -name "@*" -prune \) -o \( -name "**" \) -print | sed -n 's/\(.*\)\(\)\(.*\)/mv '"'&'"' '"'\1\3'"'/p' | bash
  • your find command will list your desired files and directories
  • sed will go through all of your lines, substitute/remove special char and set every line for bash/ash (mv) execution.

Or you can redirect sed to file and bash/ash that file (bash list_of_files_and_dirs_to_be_renamed). Test well on not imporant files/dirs before using it on real data.

3
  • 1
    That's going to break horribly on files that contain whitespace
    – roaima
    Oct 19, 2021 at 14:53
  • You are right. It can be protected adding quotes around repeat sign & sed -n 's/\(.*\)\(\)\(.*\)/mv "&" \1\3/p' I edited my post.
    – Damir
    Oct 19, 2021 at 14:58
  • I think this will properly handle both, spaces and double quotes: sed -n 's/\(.*\)\(\)\(.*\)/mv '"'&'"' '"'\1\3'"'/p'
    – Damir
    Oct 19, 2021 at 16:00

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.