Re: Spaces in UNIX Filenames 'Bad'



On Thu, 29 Dec 2005 21:28:06 +0100, fossil <marks.mail1@xxxxxxxxxxx> wrote:

  After reading several threads on this topic and facing the same
dilemma in our mixed OS environment I thought I'd post my bash
solution, for what its worth, for those wishing to eradicate these
pesky Windows files en masse. In perl the solution was fairly easy but
because of the way bash treats space characters the solution wasn't
quite as obvious.

#!/bin/bash
# get directory listing "double quoted"
string=`ls -Qa`

while (echo $string | grep \" > /dev/null)
do
   # strip first double quote character
   dblquote=`expr index "$string" \"`
   string=${string:$dblquote}
   #  get position of trailing double quote
   dblquote=`expr index "$string" \"`
   # extract filename
   filename=${string:0:$dblquote-1}
   # rename filenames with spaces
   if [[ `echo $filename | grep ' '` ]]; then
      newfilename=${filename// /_}
      mv "$filename" "$newfilename"
   fi
   # remove trailing double quote
   string=${string:$dblquote}
done

You may like to know in the future that **filename expansion** is the last expansion Bash performs on the text of a command, after word splitting.

This means that you can do:

  for filename in * .*
  do
    newname=${filename//_/ }
    if [ "$newname" != "$filename" ]
    then
      n=1
      suff=
      while [ -e "$newname$suff" ]
      do
        $suff=_$n
        n=$((n+1))
      done
      mv "$filename" "$newname$suff"
    fi
  done

This code expands the asterisk to a list of file names, and sets "filename"
to each file name in turn, without breaking up filenames that contain spaces.
The dot-asterisk expands to the names of files with a leading dot.

Notice how all subsequent use of the variable "filename" is enclosed in
quotes, because the *parameter and variable expansion" is done before
work splitting, and we don't want the file names to be split.
(The assignment to newname is a special case, that is also not split,
without need for qoutes.)

Then it creates a new name in the variable "newname", irrespective of whether
the file name contains spaces. If it does not contain spaces, the variable
"newname" will be equal to "filename".

Then it checks if the new name actually differs from the old name. If not,
there were no spaces in the old name, and nothing needs to be done.

If there are differences, it checks if a file already exists with the
new name. If so, it adds a numeric suffix to the new file name.  It repeates
the test until it finds a name that is not in use.

Then finally it renames the file

The script could still fail, if the number of files in the directory is
so large that the command line length of the shell is exceeded.  I am
not sure, though, if there is any command line length limit (except
memory availability) for *internal* bash commands.  After all, "for"
statements are not executed using an execve system call.

Another possibility is

  ls -A | while read filename
  do
    ...
  done

The "read" builtin command splits the input at newlines.  If there are more than
one variable names as arguments, the input line is split in as many words, the
last word being "the rest of the line".   Multiple contiguous spaces in the
"rest of the line" are preserved.

In this way there is not risk of running out of command line space.  This method
can fail if there are file names containing newline characters.

-Enrique
.



Relevant Pages

  • Re: why tcl/tk doesn`t incorporate tclx, tile, etc.
    ... the start of an embedded command: ... Why bash tries to expand backticks at this place, ... I'm using 3.00.0without your problem (backtick is taken literally). ...
    (comp.lang.tcl)
  • Re: Batch processing of JPEG images
    ... Shirley you can fudge it into a `find -exec` command line? ... Bash isn't my thing. ... find (filename matching regexp) -exec (command line you want to do to ... The is the placeholder where each filename is put as it's found. ...
    (uk.comp.sys.mac)
  • Re: Confused at double quote in BASH case command
    ... I am really confusded how to use double quote in BASH case command. ... Hardly a day goes by that some Googliot doesn't post multiple times, ...
    (comp.unix.shell)
  • Re: F11: Bug in sh-4.0 source build-in command
    ... source command. ... This is documented in the manpage. ... The bash builtinsmanpage states this fairly clearly: ... Read and execute commands from filename in the current shell ...
    (Fedora)
  • Re: Running commands from a variable file
    ... > That was an error from ls, not bash. ... >> the absolute paths. ... then bash sees only a command with ... to quote variables all the time. ...
    (comp.unix.shell)