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. Commented Jul 16, 2023 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. Commented Jul 16, 2023 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 Commented Jul 16, 2023 at 18:33
  • I have updated the question. Commented Jul 17, 2023 at 5:37
  • The solution is find -type d -path '*/_QWE/*/*' ! -path '*/_QWE/*/*/*' -execdir rename 's!^\./(\d+ -)\s(\d+\.)!$1!' {} \;, Thank you very much. Commented Jul 17, 2023 at 6:02
  • 1
    @AhmadIsmail I've updated my question to match your updated answer Commented Jul 17, 2023 at 11:18

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.