You are not logged in.
I have a need to use find in a for loop so I can process a number of different filetypes. Problem is these are all my old word files which are FULL of spaces (pre-Linux days). Without the for loop, my find statement works in this very simple example:
$ find . -type f \( -iname "*.doc" -o -iname "*.docx" \)
./getit.docx
./get it.doc
./getit.docBut.... with the for loop, the space messes up the find:
$ for i in `find . -type f \( -iname "*.doc" -o -iname "*.docx" \)`; do echo "$i"; done
./getit.docx
./get
it.doc
./getit.docWhat am I doing wrong?
Last edited by graysky (2011-09-05 22:20:24)
Offline
You need to quote your arguments.
[karol@black foo]$ for i in "$(find . -type f \( -iname "*.doc" -o -iname "*.docx" \))"; do echo "$i"; done
./getit.doc
./getit.docx
./get it.docI prefer $() to backtics.
Last edited by karol (2011-09-05 20:31:32)
Offline
Filenames can contain not only spaces, but newlines, too. This page is very helpful on the topic: http://mywiki.wooledge.org/BashFAQ/020
This silver ladybug at line 28...
Offline
Oh, boy...
http://mywiki.wooledge.org/BashPitfalls … .2A.mp3.29
and
http://mywiki.wooledge.org/BashFAQ/020
EDIT: lolilolicon beat me to it!
Last edited by sisco311 (2011-09-05 20:44:41)
don't drink unwashed fruit juice.
i never make predictions, especially about the future.
Offline
Wow, immediate and accurate response. Thanks guys!
A follow-up... why is my code to chop off the file extension here not working? The expected output should be the original file then the original file minus the file extension:
cat ~/bin/fix
#!/bin/bash
for i in "$(find . -type f \( -iname "*.doc" -o -iname "*.docx" \))" ; do
out="${i%.*}"
echo "$i"
echo "$out"
done
$ fix
./getit.docx
./get it.doc
./getit.doc
./getit.docx
./get it.doc
./getitLast edited by graysky (2011-09-05 20:51:59)
Offline
Offline
@falconindy - your code worked great, but I don't understand it
Is my construct doomed to fail? ..and how did I ignore the quoting on the links?
Offline
Please read the links.
In your loop the entire output of the find command is threated as a single word.
j=0; for i in "foo
bar
file"; do printf '%s\n' "$i"; ((j++)); done; printf '%d\n' $jLast edited by sisco311 (2011-09-05 21:12:03)
don't drink unwashed fruit juice.
i never make predictions, especially about the future.
Offline
find -iregex '.*\.docx?$' -printf '%f\n'...or...
find -iregex '.*\.docx?$' -exec thing_you_want_to_do {} \;Last edited by Wintervenom (2011-09-05 21:17:56)
Offline
Thanks for the tips sisco and winterv. I read the links, but I think they're written for someone with more experience/understanding. I understand what's wrong with my syntax, but I don't know how to accomplish what I want to do knowing that all the output is treated as one word.
I need to find all files ending in the following formats: .doc .docx .ppt .pptx .xls .xlsx then strip off the extension storing it in a variable, and finally process both the original files as the input of another script and keep the file stem as the output of that same script:
/path/to/script -i originalfile.docx -o originalfileLast edited by graysky (2011-09-05 21:32:40)
Offline
while IFS= read -r -d'' file
do
yourscript -i "$file" -o "${file%.*}"
done< <(find ./ -iname '*.doc' -print0)modify the find command to fit your needs.
or
If you have to run the command in the file's directory:
find ./ -iname \*.doc -execdir bash -c 'yourscript -i "$1" "${1%.*}"' _ {} \;Last edited by sisco311 (2011-09-05 21:46:51)
don't drink unwashed fruit juice.
i never make predictions, especially about the future.
Offline
@sisco - thanks for the code. The most simple test of it would be to simply echo the results, but I get a null when I do it.
while IFS= read -r -d'' file
do
echo "$file" "${file%.*}"
done< <(find ./ -iname '*.doc' -print0)Offline
I missed a space after read's -d option. Sorry.
while IFS= read -r -d '' file....don't drink unwashed fruit juice.
i never make predictions, especially about the future.
Offline
@sisco - ok, this is working. Thank you. How can I add multiple extensions to the find like I did in my first post to catch all 6 of them? The same format isn't accepted here.
Offline
It should work. Th e-print0 action must be the last:
done< <(find ./ \( -iname '*.doc' -o -iname '*docx' \) -print0)If you need a -type f test put it after the -name (-regex) tests, you don't want to check each file only the .doc, .docx .... files:
done< <(find ./ \( -iname '*.doc' -o -iname '*docx' \) -type f -print0)Last edited by sisco311 (2011-09-05 22:26:13)
don't drink unwashed fruit juice.
i never make predictions, especially about the future.
Offline
@sisco3 - FINALLY. Thanks everyone for their help with this frustrating problem.
find -regex '.*\.\(ppt\|pptx\|xls\|xlsx\|doc\|docx\)' -print0Here is the complete code:
while IFS= read -r -d '' file
do
echo "$file" "${file%.*}"
done< <(find -regex '.*\.\(ppt\|pptx\|xls\|xlsx\|doc\|docx\)' -print0)Last edited by graysky (2011-09-05 22:20:14)
Offline
I've been searching for a while now but have come up empty-handed. Can someone post a link to a guide showing additional usage of the syntax in the following line?
echo "$file" "${file%.*}"Rather than echoing the /path/to/filename.extension <<<space>>> /path/to/filename as the code above does. What would the syntax look like to echo: /path/to?
Offline
You want:
echo "${file%/*}"See the Parameter Expansion section of bash(1).
This silver ladybug at line 28...
Offline
Try 'dirname':
[karol@black ~]$ for file in $(find /home/karol/test/foo3 -type f); do echo $(dirname "$file") "$file"; done
/home/karol/test/foo3 /home/karol/test/foo3/three.baz
/home/karol/test/foo3 /home/karol/test/foo3/two.bar
/home/karol/test/foo3 /home/karol/test/foo3/one.fooOffline
Both dirname and the parameter expansion are POSIX. PE seams more 'elegant', so in this case I'd go with it. ![]()
don't drink unwashed fruit juice.
i never make predictions, especially about the future.
Offline
@lolilolicon - nice! exactly what I needed. Parameter Expansion
Offline