LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Desktop
User Name
Password
Linux - Desktop This forum is for the discussion of all Linux Software used in a desktop context.

Notices


Reply
  Search this Thread
Old 04-27-2010, 06:06 PM   #1
wallagh
LQ Newbie
 
Registered: Apr 2010
Posts: 5

Rep: Reputation: 0
automatically renamiremoving illegal characters recrusively


Hello,

I would like to replace all illegal WIndows characters in filenames, recursively. They should be replaces with underscore _
The illegal characters are:
? < > \ : * | ”

The reason being, that I can not backup my music files (genrated based on tags on an embedded linux music server) to a WIndows based Home server, because the filenames contain illegal characters (that is: for WIndows illegal, not for Linux).


Can anybody help me?
Btw. my "linux"system has only bash, nothing fancy.

Regards,


Serge W.
 
Old 04-27-2010, 07:32 PM   #2
jschiwal
LQ Guru
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,733

Rep: Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682
You can use character classes in your variable expansion.

mv -v "$file" "${file//[*?<>\\]/_}"

The backslash needs to be escaped with a backslash. The `^' character must not be the first character in the list if it is one of the characters to match. The `]' character needs to be the first character in the list or preceded with a backslash to prevent it from ending the list.

Last edited by jschiwal; 04-27-2010 at 07:33 PM.
 
Old 04-28-2010, 06:00 AM   #3
wallagh
LQ Newbie
 
Registered: Apr 2010
Posts: 5

Original Poster
Rep: Reputation: 0
Does thsi work recursively into all sub directories?





Quote:
Originally Posted by jschiwal View Post
You can use character classes in your variable expansion.

mv -v "$file" "${file//[*?<>\\]/_}"

The backslash needs to be escaped with a backslash. The `^' character must not be the first character in the list if it is one of the characters to match. The `]' character needs to be the first character in the list or preceded with a backslash to prevent it from ending the list.
 
Old 04-28-2010, 08:36 AM   #4
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
No -- that command moves a single file as in mv old_name new_name, all the -v does is make it verbose so it tells you what it is doing.

To apply it to all the files in a directory and its subdirectories and its subdirectories ... and its subdirectories the most robust technique (replace $dir as required) is
Code:
while read -r -d '' file
do
   mv -v "$file" "${file//[*?<>\\]/_}"
done < <(find $dir -type f -print0)
 
Old 04-28-2010, 12:05 PM   #5
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
I'd like to politely point out that the batch renaming of files is an exceedingly common request that has been repeatedly brought up and answered both here and elsewhere on the net. A few minutes with the LQ site search and/or Google would certainly have given you all the information you need to accomplish your goal.

Thus it's generally a good idea to first perform a few searches to discover what information is already available before starting a new thread.

Thank you.
 
Old 04-28-2010, 01:56 PM   #6
wallagh
LQ Newbie
 
Registered: Apr 2010
Posts: 5

Original Poster
Rep: Reputation: 0
If you know what yopu are looking

I understand you get tiered of questions being asked over and over again. However: I have been looking for an answer for quit a while. I have found many answers, but none was to the exact question that I had
So it was no lazyness. Perhaps ignorance....



Quote:
Originally Posted by David the H. View Post
I'd like to politely point out that the batch renaming of files is an exceedingly common request that has been repeatedly brought up and answered both here and elsewhere on the net. A few minutes with the LQ site search and/or Google would certainly have given you all the information you need to accomplish your goal.

Thus it's generally a good idea to first perform a few searches to discover what information is already available before starting a new thread.

Thank you.
 
Old 04-29-2010, 09:34 AM   #7
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
I understand. But in that case you should make it clear that you've already done some work. Perhaps show us some of the things that you've already tried. Most of us are delighted to help out people who demonstrate that they've given it their best shot, but just can't seem to get it to work out.

There really are many ways to go about this. There are several cli (and gui) batch renaming tools, for example, including at least two called simply "rename". You haven't mentioned what distro you're using, but the perl package on Debian-based distros includes a "rename" that uses the standard "s///" replacement structure.

You could combine this with find to target files recursively, for example.

Code:
find ~./musicdir -name "*.mp3" -exec rename -v 's/[?<>\\:*|"]/_/g' '{}' \+
 
Old 04-30-2010, 04:04 AM   #8
wallagh
LQ Newbie
 
Registered: Apr 2010
Posts: 5

Original Poster
Rep: Reputation: 0
not yet 100% working solution

Quote:
Originally Posted by David the H. View Post
I understand. But in that case you should make it clear that you've already done some work. Perhaps show us some of the things that you've already tried. Most of us are delighted to help out people who demonstrate that they've given it their best shot, but just can't seem to get it to work out.

There really are many ways to go about this. There are several cli (and gui) batch renaming tools, for example, including at least two called simply "rename". You haven't mentioned what distro you're using, but the perl package on Debian-based distros includes a "rename" that uses the standard "s///" replacement structure.

You could combine this with find to target files recursively, for example.

Code:
find ~./musicdir -name "*.mp3" -exec rename -v 's/[?<>\\:*|"]/_/g' '{}' \+
The Linux version that I use is embedded on my Hifidelipor music server. It simply states "linux version 2.4.26").
It does not have CC, or rename. It does have Bash.

I have tried many combinations of the sugestions, but not seem to work 100%. Most of the time, the script starts to complain about "can not rename directory" of "can not rename file".
SO in the end it is only 70% effective....
BTW I have also "replaced ":" for "\"" to replace the quot instead of the :



The latest script that I have been trying is:
Code:
#! /bin/bash


ONE=1                     # For getting singular/plural right (see below).
number=0                  # Keeps track of how many files actually renamed.
FOUND=0                   # Successful return value.
while read -r -d '' filename
do                                #      
echo "$filename" | grep -q ":"         #  Check whether filename
     if [ $? -eq $FOUND ]                   # contains :
              then
               fname=$filename                      # Strip off path.
               n=`echo $fname | sed -e "s/:/_/g"`   # Substitute dash f
               mv "$fname" "$n"                     # Do the actual rena
               let "number += 1"

	fi

done < <(find $dir -type f -print0)

if [ "$number" -eq "$ONE" ]                 # For correct grammar.
             then
               echo "$number file renamed."
             else
               echo "$number files renamed."
fi

exit 0

Last edited by wallagh; 04-30-2010 at 04:11 AM.
 
Old 05-05-2010, 01:01 AM   #9
jschiwal
LQ Guru
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,733

Rep: Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682
Look at your program as having two parts. First to select files that need renaming. And second, the renaming itself.

Your last example only changes a single character. Perhaps if you posted what some of the filenames were, or posted which illegal characters need renaming might be of help. The mv command I posted took a guess.

Also post a name of a file that didn't get renamed.
 
Old 05-06-2010, 04:50 AM   #10
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
This might do the job
Code:
#! /bin/bash

dir=$1
if [[ ! -d $dir ]];then
    echo "Directory '$dir' does not exist or is not reachable" >&2
    exit 1
fi

number=0                  # Keeps track of how many files actually renamed.
while read -r -d '' filename
do
    new_filename=$filename
    for char in '?' '<' '>' '\' ':' '*' '|' '"'
    do
        eval new_filename='${new_filename//\'$char'/_}'
    done
    if [[ $new_filename != $filename ]]; then
        if [[ -e "$new_filename" ]]; then
            echo "$new_filename already exists.  Skipping $filename" >&2
        else
            echo mv "$filename" "$new_filename"  # Remove echo after testing
            [[ $? ]] && let number++
        fi
    fi
done < <(find $dir -type f -print0)

case $number in
    1 )
        echo "$number file renamed."
        ;;
    * )
        echo "$number files renamed."
esac

exit 0
Bash's eval command is relatively slow so if there are many files to rename it may be worth experimenting to find out if it is faster to use tr once rather than the loop
Code:
    for char in '?' '<' '>' '\' ':' '*' '|' '"'
    do
        eval new_filename='${new_filename//\'$char'/_}'
    done
 
1 members found this post helpful.
Old 05-07-2010, 05:23 AM   #11
wallagh
LQ Newbie
 
Registered: Apr 2010
Posts: 5

Original Poster
Rep: Reputation: 0
single character

Quote:
Originally Posted by jschiwal View Post
Look at your program as having two parts. First to select files that need renaming. And second, the renaming itself.

Your last example only changes a single character. Perhaps if you posted what some of the filenames were, or posted which illegal characters need renaming might be of help. The mv command I posted took a guess.

Also post a name of a file that didn't get renamed.
I think you are right about the "single character" change: I already discovered that filenames with >1 illegal character failed!

The solution that I find was.... change those by hand..... About 150 filenames, so it took me a night to do so.

ANyway thanks for all the help!
 
Old 05-07-2010, 08:03 AM   #12
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Rep: Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723
I don't know how to recursively iterate over files, but this should rename them:

Code:
newname=$(dirname "$oldname")'/'$(basename "$oldname" | sed 's/[?<>\\:|*"]/_/g')

if [ -e "$newname" ]
then
	echo 'error: file '"$newname"' already exists'
	echo -n '[C]lobber, [S]kip (default), or [A]bort: '
	read input
	if [ "$input" = 'c' ]
	then
		mv "$oldname" "$newname"
	elif [ "$input" = 'a' ]
	then
		exit 0
	fi
else
	mv "$oldname" "$newname"
fi
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Checking for Illegal characters in C++ ohmygoth Programming 4 01-13-2010 01:29 PM
LXer: Mastering Characters Sets in Linux (Weird Characters, part 2) LXer Syndicated Linux News 0 11-25-2009 11:30 PM
Nagios: Illegal characters in config file TalkingMarble Linux - Software 7 10-29-2009 07:35 AM
splitting numbers and characters from an array of characters. trscookie Programming 6 11-14-2008 09:34 AM
How to modify the names of files and replace characters with other characters or symb peter88 Linux - General 2 12-10-2006 03:05 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Desktop

All times are GMT -5. The time now is 12:48 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration