I'm quite new to Linux, and I'm currently trying to organize files as they are downloaded.

Essentially I want to take .srt files from a subdirectory and move and rename them to the main directory alongside the other files.

The script I'm currently running is this:

find "/foo/bar" -type f -iname '*.srt' -exec sh -c '
    path="${1%/*}"; filename="${1##*/}";
    cp "${1}" "${path%/*}/${path##*/}.${filename}" ' sh_cp {} \;

This works well enough when the structure is like this:

├── Some.Folder.Name
    ├── Some.Video.Name.mkv
    └── Subs
        └── 2_Eng.srt

It copies 2_Eng.srt to Some.Folder.Name and renames it to Some.Folder.Name.2_Eng.srt.

However, I've encountered some .srt files that are doubly nested in folders, such as:

├── Some.Other.Folder.Name
    ├── Some.Other.Video.Name.mkv
    ├── Some.Other.Video.Name2.mkv
    └── Subs
        ├── Video1
        │   └── 2_Eng.srt
        └── Video2
            └── 2_Eng.srt

The script I'm running renames them appropriately (Video1.2_Eng.srt), but they're only moved up to the Subs directory.  I would like them to end up in Some.Other.Folder.Name.

The thread I got my script from went into a little detail about the path%/* and 1##*/ being Shell Parameter Expansion.  So is there a way to isolate the specific directory I would want the files to go to? While that directory name might change, it will always be the next level after foo/bar.

Is what I'm trying to accomplish possible?

1 Answer 1


In a sense, what you’re asking for is impossible. Consider: if find finds a name like


what should the command do?  You ‘‘know’’ that you want to move the file to


— my point is that it isn’t evident from the file name.

You have to specify where you want the files moved to:

find /foo/bar -type f -iname '*.srt' -exec sh -c '
    path="${1%/*}"; filename="${1##*/}";
    cp "${1}" "/foo/bar/${path##*/}.${filename}" ' sh_cp {} \;

If you’re putting this in a script, you’ll want to make the starting directory parameterizable.  But there’s a catch: the cp command is in a subshell that has its own argument list.  I believe that this approach is safe:

find "$1" -type f -iname '*.srt' -exec sh -c '
    path="${1%/*}"; filename="${1##*/}";
    cp "$1" "$2/${path##*/}.${filename}" ' sh_cp {} "$1" \;

This passes the starting directory, which is $1 in the script, into the subshell as a second argument, so it becomes $2.

  • Unfortunately this didn't seem to do anything. I did some further digging on how my original script works, and noticed that in all of the downloads I have the subtitle folder is called Subs. So I added dir="${1%Subs/*}"; to my second line, and changed "${1}" "${path%/*}/${path##*/}.${filename}" to "${1}" "${dir%/*}/${path##*/}.${filename}". This seems to accomplish what I need, even if it isn't the most elegant solution.
    – cam443
    Apr 2, 2022 at 19:20

You must log in to answer this question.

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