Reputation: 1
Let's say I have a directory with many subdirectories and files. I want to copy every file with a certain extension to another directory while adding the subdirectory name to the filename. For example, a .txt file at ./directory/subdirectory/example.txt would be copied to ./destinationdir/subdirectory_example.txt. The program can be a bash script, a python script, or whatever.
I have tried things like
find ./ -name '*.txt' -exec cp -r '{}' './destination/' ';'
but it doesn't add the subdirectory name to the file, and files with the same name will just get overwritten. Any solutions?
Upvotes: 0
Views: 322
Reputation: 8611
Try this:
#!/bin/bash
find . -name "*.txt" -print0 | while read -d $'\0' found
do
directoryname=$(dirname -- "$found" | cut -d'/' -f2-)
filename=$(basename -- "$found")
cp "$found" "./${directoryname}_${filename}"
done
-print0
and while read ...
ensures it will work with any weird filename you might encounter.cut
after dirname
is to remove the leading ./
that find
puts on all results.EDIT Please see comments for an explanation of why variable expansion is better than basename and dirname.
Upvotes: 1
Reputation: 19585
Have find -exec
execute an inline shell script.
find ./ -name '*.txt' -exec sh -c 'for p; do d="${p%/*}"; d="${d##*/}"; d="${d#.}"; d="${d:+${d}_}"; f="${p##*/}"; cp -- "$p" "./destinationdir/$d$f"; done' {} \+
Here is a commented fancy version of the inline shell script called by find -exec
one-liner above:
#!/usr/bin/env sh
# Iterate the arguments
for path; do
# Extract the base directory path by stripping the shortest trailing /*
base_dir="${path%/*}"
# Extract the parent directory name by stripping the longest leading */
parent_dir="${base_dir##*/}"
# Make a prefix of the parent dir name by stripping any leading dot .
prefix="${parent_dir#.}"
# If prefix is not empty, expand it with a trailing underscore _
prefix="${prefix:+${prefix}_}"
# Extract the file's base name by stripping longest leading */
base_name="${path##*/}"
# Copy the file's path at destination with new name
cp -- "$path" "./destinationdir/$prefix$base_name"
done
Upvotes: 2