I have a main directory, let’s say
main
. This main directory has some folders, among which are three folders namedccc
ddd
andlll
, which are the only folders I want to target and work on. Each of these subfolders has some folders inside which are all named the same in the three subfolders, so thatccc
ddd
lll
subfolders contain folders of the same name.Then, each of these subsubfolders that are inside
ccc
ddd
lll
has a number of files named with a certain name like thisc_000
d_000
l_000
,c_001
d_001
l_001
and so on.What I want to do first is rename these files so that the directory of their two parents will be attached in the beginning of the file name like this
ccc_foo1_c_000
ddd_foo1_d_000
lll_foo1_l_000
and so on. I’m asking if anyone can advise me how this can be done in a.sh
script?This is a simple tree structure of my main folder:
. `-- main |-- ccc | `-- foO1 | | |-- c_000 | | `-- c_001 | | -- foo2 | |-- c_000 | `-- c_001 | | |-- ddd | `-- foO1 | | |-- d_000 | | `-- d_001 | | -- foo2 | |-- d_000 | `-- d_001 |-- lll | `-- foO1 | | |-- l_000 | | `-- l_001 | | | -- foo2 | |-- l_000 | `-- l_001 | |-- aaa |-- bbb
Answer
You could do something like this:
for dir in ccc ddd lll; do
find "main/$dir" -type f -print0 |
while IFS= read -r -d '' f; do
dd=$(dirname "$f")
new="${f/main\/}"
new="${new//\//_}"
mv "$f" "$dd"/"$new"
done
done
After the above script, your files will look like this:
.
`-- main
|-- ccc
| |-- fo01
| | |-- ccc_fo01_c_000
| | `-- ccc_fo01_c_001
| `-- fo02
| |-- ccc_fo02_c_000
| `-- ccc_fo02_c_001
|-- ddd
| |-- fo01
| | |-- ddd_fo01_d_000
| | `-- ddd_fo01_d_001
| `-- fo02
| |-- ddd_fo02_d_000
| `-- ddd_fo02_d_001
`-- lll
|-- fo01
| |-- lll_fo01_l_000
| `-- lll_fo01_l_001
`-- fo02
|-- lll_fo02_l_000
`-- lll_fo02_l_001
Explanation
for dir in ccc ddd lll; do ...; done
: do this only for these three directory names, saving each of them as$dir
.find "main/$dir" -type f -print0 |
: find all files (type f
) inmain/$dir
, and print them separated by the null string (-print0
) to ensure that it works even if your file/directory names contain newlines.while IFS= read -r -d '' f; do
: this will iterate over the results offind
, saving each as$f
. TheIFS=
is needed to avoid breaking on whitespace, the-r
is so that backslashes are not treated specially and the-d ''
allows the reading of null-delimited input.dd=$(dirname "$f")
:$dd
is now the directory where the current file resides. For example,main/ccc/fo01
.new="${f/main\/}"
: this is using the shell’s string manipulation abilities to remove the stringmain/
from the file’s path.new="${new//\//_}"
: as above only now we are replacing all/
with underscores. This results in a string likeccc_fo01_c000
.mv "$f" "$dd"/"$new"
: finally, we rename the original file$f
to$dd/$new
. Remember that$dd
is the directory this file was found in and$new
is now the name you want to rename it to.
I suggest you add an echo
before the mv
to test before actually doing this.
Attribution
Source : Link , Question Author : Tak , Answer Author : terdon