I'm trying to use this question to rename all the files in a directory and keep only [a-zA-Z0-9. ] (last character is a space).

The terminal entry I'm using is:

for file in /Users/bob/Downloads/videos/*.mp4; do mv "$file" "$(sed 's/[^0-9A-Za-z. ]//g' <<< "$file")"; done

What's being done?

My current understanding, command by command, is:

[1] for file in /Users/bob/Downloads/videos/*.mp4

Creates a string variable called file which contains the text where * is, so if a file was called my (awesome) kickass! video.mp4 the variable file would be a string containing my (awesome) kickass! video.mp4

[2] do

For each file that matches the pattern (a file with an mp4 extension) do the next commands

[3] mv "$file" "$(sed)"

Use the move file command to rename the matching file

[4] "$(sed 's/[^0-9A-Za-z. ]//g'

Use the stream editor command to do a regex find/replace.

Find every character which is not in the list and replace it with what is between the two forward slashes (nothing); ie, remove non-matching characters.

[5] <<< "$file")"; done

I have no idea what the <<< operator(?) does, or what referencing back to the file variable does.

Expected Result

A file named my (awesome) kickass! video.mp4 is renamed to my awesome kickass video.mp4 and stays in the same directory

Actual Result

The file my (awesome) kickass! video.mp4 is renamed to UsersbobDownloadsvideosmy awesome kickass video.mp4 and is moved to the Users directory

  • 1
    An easy way to debug these kind of issues is to use echo to print the command with the processed/transformed data into Terminal (...; do echo mv "$file" ...) and look at the result.
    – nohillside
    Commented Oct 19, 2023 at 13:58

1 Answer 1


$file holds the absolute path, not the filename of your files.

In your example, $file would be /Users/bob/Downloads/videos/my (awesome) kickass! video.mp4. Since / is not part of the 'legal' character set, it will be removed by sed leading to the move command:

mv "/Users/bob/Downloads/videos/my (awesome) kickass! video.mp4" "UsersbobDownloadsvideosmy awesome kickass video.mp4"

When you are running the command in the terminal, your current directory is probably the user directory, meaning that the file at the absoulte path gets moved into the current directory and renamed to the name you see.

Possible fixes

  • simple workaround: add '/' to the set of 'legal' characters, so that sed wont replace it
  • other, maybe cleaner, option: change the regex in sed to only remove the given characters at the end of the path. That should be possible by using groups and having the first regex group match the directory path and the last group the filename without unwanted characters (which is the last bunch of characters without '/')
  • yet another option: before your loop, cd into the directory with the files and then iterate over *.mp4 instead of the absolute path. This should give filenames in $file making the rest of the script work as expected.
  • 2
    $ basename /Users/bob/Downloads/videos/my_video.mp4 is my_video.mp4 so OP can just use basename on "$file" in the sed invocation
    – Bakuriu
    Commented Oct 19, 2023 at 18:59
  • @Bakuriu without an appropriate cd, this would move all renamed files into the current directory.
    – nohillside
    Commented Oct 29, 2023 at 19:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .