开发者

sed command to fix filenames in a directory

I run a script which generated about 10k files in a dire开发者_开发百科ctory. I just discovered that there is a bug in the script which causes some filenames to have a carriage return (presumably a '\n' character).

I want to run a sed command to remove the carriage return from the filenames.

Anyone knows which params to pass to sed to clean up the filenames in the manner described?

I am running Linux (Ubuntu)


I don't know how sed would do this, but this python script should do the trick:.

This isn't sed, but I find python a lot easier to use when doing things like these:

#!/usr/bin/env python

import os

files = os.listdir('.')

for file in files:
  os.rename(file, file.replace('\r', '').replace('\n', ''))
  print 'Processed ' + file.replace('\r', '').replace('\n', '')

It strips any occurrences of both \r and \n from all of the filenames in a given directory.

To run it, save it somewhere, cd into your target directory (with the files to be processed), and run python /path/to/the/file.py.

Also, if you plan on doing more batch renaming, consider Métamorphose. It's a really nice and powerful GUI for this stuff. And, it's free!

Good luck!


Actually, try this: cd into the directory, type in python, and then just paste this in:

exec("import os\nfor file in os.listdir('.'):\n  os.rename(file, file.replace('\\r', '').replace('\\n', ''))\n  print 'Processed ' + file.replace('\\r', '').replace('\\n', '')")

It's a one-line version of the previous script, and you don't have to save it.


Version 2, with space replacement powers:

#!/usr/bin/env python

import os

for file in os.listdir('.'):
  os.rename(file, file.replace('\r', '').replace('\n', '').replace(' ', '_')
  print 'Processed ' + file.replace('\r', '').replace('\n', '')

And here's the one-liner:

exec("import os\nfor file in os.listdir('.'):\n  os.rename(file, file.replace('\\r', '').replace('\\n', '')replace(' ', '_'))\n  print 'Processed ' + file.replace('\\r', '').replace('\\n', '');")


If there are no spaces in your filenames, you can do:

for f in *$'\n'; do mv "$f" $f; done

It won't work if the newlines are embedded, but it will work for trailing newlines.

If you must use sed:

for f in *$'\n'; do mv "$f" "$(echo "$f" | sed '/^$/d')"; done

Using the rename Perl script:

rename 's/\n//g' *$'\n'

or the util-linux-ng utility:

rename $'\n' '' *$'\n'

If the character is a return instead of a newline, change the \n or ^$ to \r in any places they appear above.


The reason you aren't getting any pure-sed answers is that fundamentally sed edits file contents, not file names; thus the answers that use sed all do something like echo the filename into a pipe (pseudo file), edit that with sed, then use mv to turn that back into a filename.

Since sed is out, here's a pure-bash version to add to the Perl, Python, etc scripts you have so far:

killpattern=$'[\r\n]' # remove both carriage returns and linefeeds
for f in *; do
    if [[ "$f" == *$killpattern* ]]; then
        mv "$f" "${f//$killpattern/}"
    fi
done

...but since ${var//pattern/replacement} isn't available in plain sh (along with [[...]]), here's a version using sh-only syntax, and tr to do the character replacement:

for f in *; do
    new="$(printf %s "$f" | tr -d "\r\n")"
    if [ "$f" != "$new" ]; then
        mv "$f" "$new"
    fi
done


EDIT: If you really want it with sed, take a look at this:

  • http://www.linuxquestions.org/questions/programming-9/merge-lines-in-a-file-using-sed-191121/

Something along these lines should work similar to the perl below:

for i in *; do echo mv "$i" `echo "$i"|sed ':a;N;s/\n//;ta'`; done

With perl, try something along these lines:

for i in *; do mv "$i" `echo "$i"|perl -pe 's/\n//g'`; done

This will rename all files in the current folder by removing all newline characters from them. If you need to go recursive, you can use find instead - be aware of the escaping in that case, though.


In fact there is a way to use sed:

carr='\n'                                        # specify carriage return
files=( $(ls -f) )                               # array of files in current dir
for i in ${files[@]}
do 
    if [[ -n $(echo "$i" | grep $carr) ]]        # filenames with carriage return
    then
        mv "$i" "$(echo "$i" | sed 's/\\n//g')"  # move!
    fi
done

This actually works.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜