Reputation: 24708
I'm trying to use "find" to execute a command on a bunch of HTML files and then pipe out the result to a different directory. However, the pipe is failing because the filename found by "find" includes the path, and the path does not fit the directory structure of the pipe target. Essentially I need to strip the path from the second instance of {} below.
find subd/*.html -type f -exec "./mycmd {} opts > subd2/{}" \;
This is a simplified version of the command, but in the real world, putting a "../" before mysubdirectory2 will not work, nor does prefixing "cd subd && ".
Upvotes: 2
Views: 515
Reputation: 24708
Ok, I found the solution in the end, which was to use single quotes rather than double quotes, and use the $() evaluation form for basename:
find subd/*.html -type f -exec './mycmd {} opts > subd2/$(basename {})' \;
I have no idea why single quotes are the difference, or any idea why Andy's solution did not work on my machine.
Upvotes: 0
Reputation: 801
Similar to Jonathan's solution, but remove the unnecessary extra script.
find subd -name '*.html' -type f -exec sh -c '
for f; do
./mycmd "$f" opts > subd2/"${f##*/}"
done
' _ {} '+'
Upvotes: 2
Reputation: 2929
find subd/*.html -type f -exec "./mycmd {} opts > subd2/\`basename {}\`" \;
Update: Added escapes before backticks surrounding basename
Upvotes: 1
Reputation: 62469
Something like this ought to work:
while read fn
do
./mycmd "${fn}" opts > "subd2/${fn##*/}"
done < <(find subd -type f -name "*.html")
Upvotes: 1
Reputation: 754710
Time to write a script (call it mycmd-invoker
) that does the 'correct job' and run that from find
:
find subd/*.html -type f -exec mycmd-invoker {} +
The script gets given a list of file names with path and can deal with the issues:
for file in "$@"
do
base=$(basename "$file")
./mycmd "$file" opts > subd2/"$base"
done
You can throw the mycmd-invoker
script away once you're done with the task, unless you think you might need to do it again.
Upvotes: 1