2

Just as the title suggests, I want to scan a directory and all the subdirectories and remove all newline characters from the filenames.

The current solution proposed here is not working: Remove newlines in file names

This is what I got when I used it:

$ find -name $'*\n*' -exec rename $'s|\n| |g' '{}' \; 
rename: not enough arguments 
Try 'rename --help' for more information.

if I add a *

$ find -name $'*\n*' -exec rename $'s|\n| |g' '{}' * \;

this does not produce any error messages (just accepts the command) but it does not rename the file in the subdirectory

  • 1
    In which way your cited answer isn't working? Can you add some console output of it? – 41754 Sep 18 '19 at 12:01
  • 1
    Are you sure it's newline \n you want to remove? Apparently, in the question you linked to, the relevant characted was "carriage return" \r instead. Maybe that's what you need too? – NickD Sep 18 '19 at 12:11
  • Please edit your question and put additional details there. – Murphy Sep 18 '19 at 12:28
  • Based on the error message, it looks like rename on your system is the util-linux implementation (whereas the linked answer assumes one of the Perl-based implementations). What type or flavor of Unix / Linux are you using? – steeldriver Sep 18 '19 at 13:17
  • Thanks @steeldriver, I am using the latest Manjaro KDE. I was not aware there is a difference. When I run $ rename --version

    I get rename from util-linux 2.34

    – Georgios Mavropalias Sep 18 '19 at 13:33

2 Answers2

3

Make sure you use one of the perl-based rename variants, sometimes called prename, not the one from util-linux (sometimes called rename.ul).

The one from util-linux is much more limited (despite being much newer), uses a different syntax, can only replace fixed strings and can't replace all the occurrences of a string.

Here, I'd use perl rename variants, make sure to only convert newlines in the file names, not the directory components leading to them, and use -depth to process leaves before branches.

perl recognises \n as meaning a newline, so you don't need to use $'...' for its code argument (though it's fine if you do contrary to what I initially thought).

find . -depth -name $'*\n*' -exec rename '
  s{[^/]*\z}{$& =~ y/\n/ /r}e' '{}' +

Or use -execdir if available (though that will run at least one rename per directory with files with \n within):

find . -depth -name $'*\n*' -execdir rename 'y/\n/ /' {} +

Or you could use zsh's zmv:

autoload zmv
NL=$'\n'
zmv "(**/)(*$NL*)(#qD)" '$1${2//$NL/ }'

(which contrary to the find-based approaches will still work even if file names contain sequences of bytes that don't form valid characters. It will also bail out without doing anything if it detects a conflict).

2

The usage of the rename command provided by util-linux is different from that given in the answer you linked. In particular, it requires a separate from and to argument rather than a single sed-style replacement command - hence the error message not enough arguments.

SYNOPSIS
       rename [options] expression replacement file...

So in this case you would need

find . -name $'*\n*' -exec rename $'\n' ' ' {} \;

See also:

and for a simple usage comparison

steeldriver
  • 81,074