3

Is there a way to recursively remove a carriage return \r character that has been appended to thousands file names across a hierarchy of dozens of folders? Also, not all files were affected.

For example, the ls command shows Cymbal2.wav?, where the ? is a \r character.

I'm running MacOS, so if this not the right forum...

7

A variation on @Gilles' answer that removes all CR characters in (non-hidden) file names wherever they are.

autoload -Uz zmv # best in ~/.zshrc
zmv $'(**/)(*\r*)' $'$1${2//\r}'

(from within the top-level directory where those files are).

Here, we don't want to use $f as it's important we only change the name of the files and not other pathname components as mv $'a\rb/c\rd' ab/cd wouldn't work. We need first to do mv $'a\rb/c\rd' $'a\rb/cd' and then mv $'a\rb' ab which zmv does as it processes recursive globs depth first (adds the (#qoD) qualifier).

$1 and $2 above recall what is captured by the (...)s in the pattern, so $1 has the dirname, and $2 the basename.

6

For mass-renaming (or mass-copying) files, zmv is your friend.

autoload zmv
zmv -W $'**/*\r' '**/*'

Explanations:

  • zmv renames files matching the given wildcard pattern (here $'**/*\r') to the given replacement expression (here **/*).
  • The -W option allows wildcards in the replacement expression.
  • The $'…' syntax supports backslash expressions such as \r for a carriage return.
  • **/* matches every file at any level under the current directory (** is for recursive globbing.

Alternatively:

autoload zmv
zmv $'**/*\r' $'${f%\r}'

$f stands for the original file name and the ${VARIABLE%SUFFIX} parameter expansion form strips off the given suffix.

Recommendation for your .zshrc:

autoload zmv
alias zcp='zmv -C'
alias zln='zln -L'
1

As explained in the comment this works on Linux but not by default on MacOS.

touch $'file_\r_name'

ls -l --quoting-style=c file_*
-rw-r--r-- 1 hl hauke 0 23. Nov 17:02 "file_\r_name"

find . -name $'*\r*' -exec rename -nv $'\r' '' {} + 2>/dev/null | cat -v
`./file_^M_name' -> `./file__name'

-nv puts rename in verbose dry run mode.

cat -v is (more or less) necessary because the \r makes the output look quite strange (because the part after the \r overwrites the part before).

2
  • It should perhaps be noted that it's the util-linux version of rename that's used here, not the Perl one. rename -n -v 's/\r$//' {} + should work with the Perl one.
    – ilkkachu
    Nov 24 '21 at 8:22
  • 1
    This would work on Linux, but the asker specified macOS, where util-linux rename is definitely not available. A perl rename may be available from a popular package source; Homebrew has one, but it's not the same as rename/prename on Debian. Nov 24 '21 at 8:52

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.