Here's the TLDR version of my solution: you can use the dirname
and basename
commands along with process substitution in order to construct the target path for your copy command.
A longer explanation follows.
Here is a (super verbose) script that does roughly what you want using a Bash loop:
#!/bin/bash
# copy_and_rename.bash
#
# Copy multiple files 2 folders up and rename these files
# to contain their parent directory as a prefix.
#
# Set internal field separator to handle spaces in file names
IFS=$'\n'
# Iterate over the list of file paths
for _file_path in $@; do
# Get the file name
_file_name="$(basename ${_file_path})"
echo "${_file_name}"
# Get the path to the target directory (two levels above the file)
_target_directory_path=$(dirname $(dirname ${_file_path}))
echo "${_target_directory_path}"
# Get the parent directory of the target directory
_parent_directory_path=$(dirname ${_target_directory_path})
echo "${_parent_directory_path}"
# Get the name of the parent directory
_parent_directory_name=$(basename ${_parent_directory_path})
echo "${_parent_directory_name}"
# Construct the new file path
_new_file_path="${_target_directory_path}/${_parent_directory_name}_${_file_name}"
echo "${_new_file_path}"
# Copy and rename the file
echo "cp -i \"${_file_path}\" \"${_new_file_path}\""
cp -i "${_file_path}" "${_new_file_path}"
echo
done
You can obviously compress this a lot, but I kept it this way for explanatory value.
Here is what the preceding script looks like without any comments or superfluous variables or echo
statements:
for _file_path in $@; do
cp -i "${_file_path}" \
"$(dirname $(dirname ${_file_path}))/$(basename $(dirname $(dirname $(dirname ${_file_path}))))_$(basename ${_file_path})"
done
It's very fragile and doesn't do much in the way of error-handling. I also left in some echo
statements for debugging so you see what it's doing and can sanity-check it when you run it for the first time.
To test it I created your files by using the following script, which I include here in case you find it useful for further testing:
#!/bin/bash
# create_test_files.bash
# Set internal field separator to handle spaces in file names
IFS=$'\n'
# Choose an prefix for the file paths
_prefix="/tmp"
# Create array of sample files
_sample_files=(
"/samples/mydata1/RUN1/ID_date/PCR2/TIME1/F3.bam"
"/samples/mydata2/RUN1/ID2_date4/PCR2/TIME7/F3.bam"
"/samples/mydataxxx/RUN1/IDxxx_datexxx/PCR2/TIMExxx/F3.bam"
)
# Create directories and files
for _file in "${_sample_files[@]}"; do
# Add the prefix to the path
_path="${_prefix}${_file}"
# Create parent directory
mkdir -p "$(dirname ${_path})"
# Create file
touch "${_path}"
done
I check that the files were created properly by using the find
command:
$ find /tmp/samples -type f
/tmp/samples/mydata1/RUN1/ID_date/PCR2/TIME1/F3.bam
/tmp/samples/mydata2/RUN1/ID2_date4/PCR2/TIME7/F3.bam
/tmp/samples/mydataxxx/RUN1/IDxxx_datexxx/PCR2/TIMExxx/F3.bam
Then I invoke the script like this:
bash copy_and_rename.bash \
/tmp/samples/mydata1/RUN1/ID_date/PCR2/TIME1/F3.bam \
/tmp/samples/mydata2/RUN1/ID2_date4/PCR2/TIME7/F3.bam \
/tmp/samples/mydataxxx/RUN1/IDxxx_datexxx/PCR2/TIMExxx/F3.bam
And then I check that the script worked by using find
again:
$ find /tmp/samples -type f
/tmp/samples/mydata1/RUN1/ID_date/PCR2/ID_date_F3.bam
/tmp/samples/mydata1/RUN1/ID_date/PCR2/TIME1/F3.bam
/tmp/samples/mydata2/RUN1/ID2_date4/PCR2/ID2_date4_F3.bam
/tmp/samples/mydata2/RUN1/ID2_date4/PCR2/TIME7/F3.bam
/tmp/samples/mydataxxx/RUN1/IDxxx_datexxx/PCR2/IDxxx_datexxx_F3.bam
/tmp/samples/mydataxxx/RUN1/IDxxx_datexxx/PCR2/TIMExxx/F3.bam
Finally, I delete all of the test files, also using find
:
find /tmp/samples -type f -exec rm {} \;