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).

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
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
  • 78,509
  • 12
  • 109
  • 152