-2

copy directory with a matched pattern of parent directories

cp 
dir/group1/sub01/./././DCM
dir/group2/sub01/././DCM
to 
dir/Base/group1/sub01/Time1/
dir/Base/group2/sub01/Time1/
with matched group name and sub name
output: 
dir/Base/group1/sub01/Time1/DCM
dir/Base/group2/sub01/Time1/DCM

I was thinking maybe

find * -type d -name "DCM" -execdir bash -c 'old="$1"; new="$(cd ../../..; basename --"$PWD")/$(cd ../..; basename --"$PWD")"; cp -r "$old" "dir/Base/$new"' - {} \;

Any suggestions?

zeno Zeng
  • 3
  • 2

3 Answers3

0

Instead of writing long complex lines I will offer you to do it with awk:

new_dir=$(echo "$dir" | awk -F\/ '{print "dir/Base/"$2"/"$3"/Time1/"}')

and the script may become:

while read dir
do
  new_dir=$(echo "$dir" | awk -F\/ '{print "dir/Base/"$2"/"$3"/Time1/"}')
  cp -fdR "$dir" "$new_dir"
done <(find . -type d -name DCM)
Romeo Ninov
  • 17,484
0

Using zsh:

autoload -U zmv
zmv -v -C -o -R -- 'dir/(group<->)/(sub<->)/**/DCM' 'dir/Base/$1/$2/Time1/'

The zmv command above takes an extended globbing pattern and a destination pathname. The globbing pattern may contain "capture groups" (parenthesized expressions) that you may refer to with $1, $2, etc. in the destination pathname. The command above captures the names of the group and sub subdirectories (where <-> matches any number).

The options used here are -n for a "dry-run" (don't actually carry out any copying; remove this when certain that it works), -v for "verbose" operation, and -C to do copying rather than moving. We use -o -R to pass -R to cp.

Testing:

$ tree
.
`-- dir
    |-- Base
    |   |-- group1
    |   |   `-- sub01
    |   |       `-- Time1
    |   `-- group2
    |       `-- sub01
    |           `-- Time1
    |-- group1
    |   `-- sub01
    |       `-- a
    |           `-- b
    |               `-- c
    |                   `-- DCM
    `-- group2
        `-- sub01
            `-- a
                `-- b
                    `-- DCM
$ zmv -v -C -o -R -- 'dir/(group<->)/(sub<->)/**/DCM' 'dir/Base/$1/$2/Time1/'
cp -R -- dir/group1/sub01/a/b/c/DCM dir/Base/group1/sub01/Time1/
cp -R -- dir/group2/sub01/a/b/DCM dir/Base/group2/sub01/Time1/
$ tree
.
`-- dir
    |-- Base
    |   |-- group1
    |   |   `-- sub01
    |   |       `-- Time1
    |   |           `-- DCM
    |   `-- group2
    |       `-- sub01
    |           `-- Time1
    |               `-- DCM
    |-- group1
    |   `-- sub01
    |       `-- a
    |           `-- b
    |               `-- c
    |                   `-- DCM
    `-- group2
        `-- sub01
            `-- a
                `-- b
                    `-- DCM
Kusalananda
  • 333,661
-1

Something like this might work:

#!/bin/bash

set -e -o pipefail

find . -type d -name DCM | while read dir; do new_dir_suffix=echo &quot;$dir&quot; | sed 's/^.*group/group/' | sed 's|\(sub[0-9]*\).*DCM|\1/Time1|' cp -fdR "$dir" dir/base/"$new_dir_suffix" done

Setting variables in bash -c commands won't work because the variables only exist within the context of those Bash invocations. There's no way to set environment variables from find.

  • You can pass variables into a bash -c script. ... -exec bash -c 'some looping code' bash {} +. See also https://unix.stackexchange.com/questions/321697 – Kusalananda Mar 02 '22 at 09:20