LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices



Reply
 
Search this Thread
Old 04-01-2011, 06:26 PM   #1
cgcamal
Member
 
Registered: Nov 2008
Location: Tegucigalpa
Posts: 72

Rep: Reputation: 16
How to handle files with spaces in their names in bash?


Hi all,

*I'm using Ubuntu 10.10

My issue is I can't handle the files with spaces in their name, I've donde the below script to print each file
found inside folder and subbfolders with "find".

I would like to "ls" to each file found with its complete path and with its basename too.

Code:
files=$(find . -type f)

for each in "$files"
do
ls -l "$each" # 1rst option I've tried to list with full path
ls -l "$(/bin/echo "$each")" # 2nd option I've tried to list with full path
ls -l "$(/bin/echo $(basename "$each"))" # 1nd option I've tried to list with it basename
ls -l "$(/bin/echo "$(basename "$each")")" # 2nd option I've tried to list with it basename
done
All of the "ls -l" options above I've tried, give me errors (ls: cannot access...) if there is at least one file within $files list, with spaces in the filename.

How can I list "ls -l" in both cases (with full path and with basename) when there are files with spaces in their name?

Thanks in advance,

Regards.
 
Old 04-01-2011, 06:53 PM   #2
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943
The safe method is to use EOS (zero) as a separator, and read them to an array:
Code:
#!/bin/bash
find . -type f -print0 | (
    while read -d "" FILE ; do FILES=("${FILES[@]}" "$FILE") ; done

    echo "Found ${#FILES[@]} files:"
    for FILE in "${FILES[@]}" ; do
        echo "'$FILE'"
    done
)
Remember to use doublequotes around the file names when using them as a parameter. For example, to list all the files, you can use
Code:
#!/bin/bash
find . -type f -print0 | (
    while read -d "" FILE ; do FILES=("${FILES[@]}" "$FILE") ; done

    ls -laF "${FILES[@]}"
)
or
Code:
#!/bin/bash
find . -type f -print0 | (
    while read -d "" FILE ; do FILES=("${FILES[@]}" "$FILE") ; done

    for FILE in "${FILES[@]}" ; do
        ls -laF "$FILE"
    done
)
which are otherwise equivalent, except the latter one uses a loop, listing each file separately, while the previous one gives the ls command all the file names in one go.

Hope this helps.
 
Old 04-01-2011, 09:59 PM   #3
cgcamal
Member
 
Registered: Nov 2008
Location: Tegucigalpa
Posts: 72

Original Poster
Rep: Reputation: 16
Quote:
Originally Posted by Nominal Animal View Post
The safe method is to use EOS (zero) as a separator, and read them to an array:
Code:
#!/bin/bash
find . -type f -print0 | (
    while read -d "" FILE ; do FILES=("${FILES[@]}" "$FILE") ; done

    echo "Found ${#FILES[@]} files:"
    for FILE in "${FILES[@]}" ; do
        echo "'$FILE'"
    done
)
Hi Nominal_A,

Thanks for your reply. It works nice!


I understand better now why you introduced the option print0.
Code:
-print0 True; print the full file name on the standard output, followed  by a null character (instead of the newline character that '-print'  uses). This allows file names that contain newlines or other types of white space to be  correctly interpreted by programs that process the find output. This option corresponds to the '-0' option of xargs.
Now I have 2 questions:
1-)May you explain how the array is loaded with this syntax? How it works?
Code:
FILES=("${FILES[@]}" "$FILE")
2-) How can be introduce the basename option?
I've tried:
Code:
    ls -laF "$(basename ${FILES[@]})"
and
Code:
    ls -laF "${basename FILES[@]}"
But doesn't work.

Thanks in advance,

Regards.
 
Old 04-01-2011, 10:45 PM   #4
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943
Quote:
Originally Posted by cgcamal View Post
1-)May you explain how the array is loaded with this syntax? How it works?
Code:
FILES=("${FILES[@]}" "$FILE")
The statement replaces the list in variable FILES with another list. The new list contains each and every one of the old list items, plus one new one, $FILE. For Bash, "${list[@]}" expands to each of the list elements as a separate token. Quotes are important, since Bash uses them to understand which ones are supposed to be separate tokens.

Quote:
Originally Posted by cgcamal View Post
2-) How can be introduce the basename option?
You will need to loop thorough the FILES array, and apply basename separately to each one:
Code:
for FILE in "${FILES[@]}" ; do
    BASE="`basename "$FILE"`"

    ls -laF "$BASE"
done
If you want, you can also create a parallel array containing only the base names:
Code:
BASENAMES=()
for FILE in "${FILES[@]}" ; do
    BASENAME=("${BASENAMES[@]}" "`basename "$FILE"`")
done
after which you can run any command and supply all the base names to it:
Code:
ls -laF "${BASENAMES[@]}"
If you have multiple parallel arrays like FILES and BASENAMES above, and you want to loop thorough them, you'll want to use this:
Code:
for ((I=0; I<${#FILES[@]}; I++)) ; do
    FILE="${FILES[I]}"
    BASE="${BASENAMES[I]}"

    # Do something with $FILE and $BASE ... 
done
Note that ${#FILES[@]} evaluates to the number of items in FILES, and in Bash arrays, indexes start from zero.
 
1 members found this post helpful.
Old 04-02-2011, 12:09 AM   #5
cgcamal
Member
 
Registered: Nov 2008
Location: Tegucigalpa
Posts: 72

Original Poster
Rep: Reputation: 16
Hi NA,

Very, very, very helpful.

Really thanks for your kindly and clear explanation.

I'll try to practice this concepts asap to understand better.

Really thanks.

Regards.
 
Old 04-02-2011, 03:57 AM   #6
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,698

Rep: Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988
I would also add that you could have it all done with your find:
Code:
find . -type f -ls -printf "basename is %f\n"
Also, you can append to a bash array using += notation as well:
Code:
FILES+=("$FILE")
 
1 members found this post helpful.
Old 04-02-2011, 06:42 AM   #7
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943
Quote:
Originally Posted by grail View Post
Also, you can append to a bash array using += notation as well:
Code:
FILES+=("$FILE")
I think that only works in Bash 3 and newer. I frequently use systems with an older version of Bash, so I always try to make my scripts compatible.

Unfortunately, I cannot find reliable documentation for older versions of Bash -- even Waybackmachine is glitching right now --, so I'm not sure. If you find a good source for previous bash manuals, I'd appreciate it.
 
  


Reply

Tags
bash, filename, quoting, space


Thread Tools Search this Thread
Search this Thread:

Advanced Search

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
[SOLVED] Bash file names with spaces alex1986 Programming 5 07-26-2010 10:47 PM
bash - replace all spaces in file, folder names babag Programming 24 04-20-2008 01:17 AM
how to handle file names with spaces in them bahadur Programming 14 04-04-2005 01:04 PM
how to handle file names with spaces in them bahadur Programming 3 03-23-2005 06:15 AM
Bash crashes ? File names with () and spaces Danodare Slackware 1 02-27-2004 03:50 PM


All times are GMT -5. The time now is 05:18 AM.

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
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration