1

I can run a command in all directories named _QWE using:

find . -name '_QWE' -type d -execdir touch {}/1234.txt \;

However, I need to run -execdir rename 's!^\./(\d+ -)\s(\d+\.)!$1!' {} \; in all the immediate sub-directories of _QWE to rename the sub-directories of the sub-directories of _QWE.

I mean suppose I have a directory structure like:

├── folder_1
│   └── _QWE
│       ├── Course 1
│       │   ├── 1 - Introduction
│       │   ├── 2 - 1. Basics of Course 1
│       │   ├── 3 - 2. Conclusion of Course 1
│       ├── Course 2
│       │   ├── 1 - Introduction
│       │   ├── 2 - 1. Basics of Course 2
│       │   ├── 3 - 2. Conclusion of Course 2
├── folder_2
│   └── folder_3
│      └── _QWE
│          ├── Course X1
│          │   ├── 1 - Introduction
│          │   ├── 2 - 1. Basics of Course X1
│          │   ├── 3 - 2. Conclusion of Course X1
│          ├── Course X2
│          │   ├── 1 - Introduction
│          │   ├── 2 - 1. Basics of Course X2
│          │   ├── 3 - 2. Conclusion of Course X2

Here I want to rename:

1 - Introduction
2 - 1. Basics of Course 1
3 - 2. Conclusion of Course 1
1 - Introduction
2 - 1. Basics of Course 2
3 - 2. Conclusion of Course 2
1 - Introduction
2 - 1. Basics of Course X1
3 - 2. Conclusion of Course X1
1 - Introduction
2 - 1. Basics of Course X2
3 - 2. Conclusion of Course X2

Here for example, 3 - 2. Conclusion of Course X2 will be renamed to 3 - Conclusion of Course X2. This is what 's!^\./(\d+ -)\s(\d+\.)!$1!' does.

Just to be clear, 3 - 2. Conclusion of Course X2 is a directory name and not file name.

How can I do that?

Update 1:

I could get the paths using:

for dir in $(find . -name '_QWE' -type d)/*/ ; do echo $dir ; done

or,

for dir in $(find . -name '_QWE' -type d)/*/ ; do (cd "$dir"; pwd); done

But,

for dir in $(find . -name '_QWE' -type d)/*/*/ ; do rename 's!^\./(\d+ -)\s(\d+\.)!$1!' $dir ; done

Not yielding any output.

1
  • 1
    for dir in $(find ...) is a bad idea. See Why is looping over find's output bad practice?. Use find's -exec/-execdir or use readarray/mapfile to populate an array with NUL-separated output from find, then iterate over the array. BTW, rename produces no output on stdout unless you tell it to with the -v option. Also, if you want only the immediate sub-dirs of _QWE then use find's -maxdepth 1 option.
    – cas
    Jul 16 at 7:40

1 Answer 1

1

You could use the -path modifier to pick out directories immediately under the matching directories:

find . -depth -type d -path '*/_QWE/*/*' ! -path '*/_QWE/*/*/*' -exec rename 's!(/\d+)\s+-\s+\d+\.\s+([^/]*)$!$1 $2!' {} +

I have modified your RE slightly to anchor it to the filename component of the matched path. (For PCRE expressions as used here, \s+ matches one or more whitespace characters; \d+ matches one or more digits; [^/]* matches a run of zero or more characters except /.)

Using your example tree of directories, here is the corresponding output when using rename -n:

./folder_1/_QWE/Course 1/2 - 1. Basics of Course 1 renamed as ./folder_1/_QWE/Course 1/2 Basics of Course 1
./folder_1/_QWE/Course 1/3 - 2. Conclusion of Course 1 renamed as ./folder_1/_QWE/Course 1/3 Conclusion of Course 1
./folder_1/_QWE/Course 2/2 - 1. Basics of Course 1 renamed as ./folder_1/_QWE/Course 2/2 Basics of Course 1
./folder_1/_QWE/Course 2/3 - 2. Conclusion of Course 1 renamed as ./folder_1/_QWE/Course 2/3 Conclusion of Course 1
./folder_2/folder_3/_QWE/Course X1/2 - 1. Basics of Course 1 renamed as ./folder_2/folder_3/_QWE/Course X1/2 Basics of Course 1
./folder_2/folder_3/_QWE/Course X1/3 - 2. Conclusion of Course 1 renamed as ./folder_2/folder_3/_QWE/Course X1/3 Conclusion of Course 1
./folder_2/folder_3/_QWE/Course X2/2 - 1. Basics of Course 1 renamed as ./folder_2/folder_3/_QWE/Course X2/2 Basics of Course 1
./folder_2/folder_3/_QWE/Course X2/3 - 2. Conclusion of Course 1 renamed as ./folder_2/folder_3/_QWE/Course X2/3 Conclusion of Course 1

For testing, I also added a sample set of directories using the same names under a folder_4 but not under a directory _QWE. As expected these were correctly ignored.

5
  • I need to rename the sub-directories. It finds the sub-directories if I use find -type d -path '*/_QWE/*' ! -path '*/_QWE/*/*'. For example, ./folder_1/_QWE/FolderName. Here I need to change the FolderName. But then the rename command does not change anything. Jul 16 at 17:47
  • @AhmadIsmail the question implies you want to rename files. Update the question to make it clear what you want - ideally including some examples - and I'll see if I can amend the answer to match the new requirement. In particular make it clear that you want to rename subdirectories of _QWE, if that indeed is what you want to do Jul 16 at 18:33
  • I have updated the question. Jul 17 at 5:37
  • The solution is find -type d -path '*/_QWE/*/*' ! -path '*/_QWE/*/*/*' -execdir rename 's!^\./(\d+ -)\s(\d+\.)!$1!' {} \;, Thank you very much. Jul 17 at 6:02
  • 1
    @AhmadIsmail I've updated my question to match your updated answer Jul 17 at 11:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .