how to handle file names with space characters in a shell script?
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
how to handle file names with space characters in a shell script?
I'm a complete newbie to *nix.
I'm trying to write a script to symlink my windows files, but my script doesn't work if there're space characters in their names:
Code:
#!/bin/bash
#replace all space characters with '\ '
string=${@// /\\ }
#strip ''
string=${string%'}
string=${string#'}
echo $string > ~/linkfilename_log
ln -fs $string /tmp/temp_target
(This code is written from memory in windows, as I can't get my network working in BSD, yet)
I saved this script as 'linkfilename' in my scripts folder, and I linked my data files with the following command in Thunar :
Code:
linkfilename "%F"
if my file name is 'filename_with_space.cpt', the script works, but
if it is 'filename with space.cpt', it doesn't.
,
the file is linked. And 'filename\ with\ space.cpt' is exactly what I see in my 'linkfilename_log' file.
FYI, I have to load my files in a windowz application running in Wine, but I can't load files with space characters in thier names if I don't change their names or link them as in the script.
I know that it's very easy to convert all space characters with '_' in Thunar, but I'd like to keep them as they are if possible.(this is not my personal taste, there are good reasons.)
You can still run into a problem if you need to run the names through a pipe. Such as a directory with 50k entries in it where you can't use file globbing (due to memory restrictions). In this case a common technique is to use the find command to print the filenames and use '-print0' to separate the names with the NULL character. On the other side of the pipe, xargs uses the -0 argument to use NULL as a delimiter. It also has arguments you can use to limit the number of arguments handled at once.
You also need to watch out for other characters as well such as (,),{,} which have special meanings to the shell. The worst character is "!" when working in an interactive shell. A filename beginning with a hyphen can cause problems as well.
If you have a list of filenames, perhaps the results of a sed command, you can use "tr '\n' '\0'" to produce the same nulls as find's "-print0" argument.
Example finding and deleting duplicate files:
Code:
find directory/ -type f -exec md5sum '{}' \; | # prints out all of the files, one per line
sort | # sorts out the results
uniq -d -w32 | # compares the md5sums and prints out duplicates
tr '\n' '\0' | # converts newlines to nulls to eliminate problems with spaces in filenames
xargs -0 -L 50 rm # removes the duplicates
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195
Rep:
Quote:
Originally Posted by jschiwal
You also need to watch out for other characters as well such as (,),{,} which have special meanings to the shell. The worst character is "!" when working in an interactive shell. A filename beginning with a hyphen can cause problems as well.
.. which indicates that when Unix was designed, assumptions were made about the knowledge level of users, in the sense that certain characters in a file name should not be used. Still I would *never* use a file name which contains other characters than [A-z0-9._\-], not on either platform.
But.. MAC is even worse. Once I had to view a CD with picture files on a Windows machine which was created on the MAC and contained "?" in the file names. No way Windows would read that, but in Linux I was able to convert the file names (with rename and friends) to something usable in Windows.
More radical, change the spaces to underscores & solve the problem permanently:
Code:
ls |grep \ |while read F; do mv \"$F\" \"`echo $F|tr \ _`"; done
Edit: Oops, that code doesn't work -- I should have removed the backslashes in the mv statement (they are an artifact of wrapping that mv statement in an echo during testing):
Here is the correct code:
Code:
ls |grep \ |while read F; do mv "$F" "`echo $F|tr \ _`"; done
.. which indicates that when Unix was designed, assumptions were made about the knowledge level of users, in the sense that certain characters in a file name should not be used. Still I would *never* use a file name which contains other characters than [A-z0-9._\-], not on either platform.
But.. MAC is even worse. Once I had to view a CD with picture files on a Windows machine which was created on the MAC and contained "?" in the file names. No way Windows would read that, but in Linux I was able to convert the file names (with rename and friends) to something usable in Windows.
jlinkels
The font encoding is probably different between the Mac and Windows. I think a highlighted ? is printed if a character is used that isn't in your character set.
Imagine if you have a filesystem from a PPC machine using UTF-16 and then mount it on a X86 machine. The byte order of the characters will be different.
In my opinion, the best way to handle spaces in a script is to change the internal field separator. I get headaches trying to get quoting to work correctly, and I often just can't seem to get them right. But changing the IFS so that it doesn't recognize spaces as separators generally does the trick.
Note that the new IFS is simply a newline. The original is newline+tab+space. Actually, you probably won't need to save the original IFS, because the script runs in its own subshell and doesn't affect anything else, but it's a good idea if you need to change it back while inside the script for some reason, such as if you have to do a loop with a space-separated list of items.
PS: Not to sound too critical, but this topic comes up quite often, so you would've saved us all some effort if you'd searched the forums first.
I suppose I should thank you for pointing me at an error my code above;
but given that it wouldn't work even on files,
I have to wonder if you even tried it before asking if would work on directories.
The answer is that in *nix directories are files, so the corrected code works on either, as is.
If you want a demonstration, try this:
Code:
mkdir -p test/test
cd test/test
touch tfile\ {1..9}
mkdir tdir\ {1..9}
ls; sleep 5 # verify test corpus
ls |grep \ |while read F; do mv "$F" "`echo $F|tr \ _`"; done
ls; sleep 5 # verify results
cd ..
rm -rf test # remember how dangerous this is
Note: I did test this -- inside a parent directory also named "test" -- but you still want to be very careful around anyrm -rf
I suppose I should thank you for pointing me at an error my code above;
but given that it wouldn't work even on files,
I have to wonder if you even tried it before asking if would work on directories.
The answer is that in *nix directories are files, so the corrected code works on either, as is.
Hmmm, you're welcome???
I did in fact test your code on directories and it failed. That's why I asked my question. I did not know directories are files.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.