3

I have the following files and directories:

/tmp/jj/
/tmp/jj/ese
/tmp/jj/ese/2010
/tmp/jj/ese/2010/test.db
/tmp/jj/dfhdh
/tmp/jj/dfhdh/2010
/tmp/jj/dfhdh/2010/rfdf.db
/tmp/jj/ddfxcg
/tmp/jj/ddfxcg/2010
/tmp/jj/ddfxcg/2010/df.db
/tmp/jj/ddfnghmnhm
/tmp/jj/ddfnghmnhm/2010
/tmp/jj/ddfnghmnhm/2010/sdfs.db

I want to rename all 2010 directories to their parent directories then tar all .db files...

What I tried is:

#!/bin/bash

if [ $# -ne 1 ]; then
    echo "Usage: `basename $0` <absolute-path>"
    exit 1
fi

if [ "$(id -u)" != "0" ]; then
    echo "This script must be run as root" 1>&2
    exit 1
fi
rm /tmp/test

find $1 >> /tmp/test
for line in $(cat /tmp/test)
do
    arr=$( (echo $line | awk -F"/" '{for (i = 1; i < NF; i++) if ($i == "2010") print $(i-1)}') )
    for index in "${arr[@]}"
    do
    echo $index #HOW TO WRITE MV COMMAND RATHER THAN ECHO COMMAND?
    done
done

1) The result is:

ese


dfhdh


ddfxcg


ddfnghmnhm

But it should be:

ese
dfhdh
ddfxcg
ddfnghmnhm

2) How can I rename all 2010 directories to their parent directory? I mean how to do (I want to do it in loop because of larg numbers of dirs):

mv /tmp/jj/ese/2010 /tmp/jj/ese/ese
mv /tmp/jj/dfhdh/2010 /tmp/jj/dfhdh/dfhdh
mv /tmp/jj/ddfxcg/2010 /tmp/jj/ddfxcg/ddfxcg
mv /tmp/jj/ddfnghmnhm/2010 /tmp/jj/ddfnghmnhm/ddfnghmnhm
MLSC
  • 5,872
  • 8
  • 55
  • 89

4 Answers4

2

You could instead use find in order to determine if a directory contains a subdirectory named 2010 and perform the mv:

find /tmp -type d -exec sh -c '[ -d "{}"/2010 ] && mv "{}"/2010 "{}"/$(basename "{}")' -- {} \;

I'm not sure if you have any other question here but this would do what you've listed at the end of the question, i.e. it would:

mv /tmp/jj/ese/2010 /tmp/jj/ese/ese

and so on...

devnull
  • 118,548
  • 33
  • 236
  • 227
  • Thank you..There were two questions...with your answer how can I edit my script..can you do that please? – MLSC Apr 13 '14 at 07:51
  • @MortezaLSC If I understand the question correctly, then you'd need to replace the first parameter passed to your script in the `find` command mentioned above. – devnull Apr 13 '14 at 07:53
  • 1
    `find`'s `{}` placeholder is not supposed to be used in that way. Imagine there's a file with a quote and an evil command in it and you're screwed! All your `{}`'s inside your `sh` command should be replaced with `$1`. – gniourf_gniourf Apr 13 '14 at 16:46
2

Can be done using grep -P:

grep -oP '[^/]+(?=/2010)' file
ese
ese
dfhdh
dfhdh
ddfxcg
ddfxcg
ddfnghmnhm
ddfnghmnhm
anubhava
  • 761,203
  • 64
  • 569
  • 643
1

First, only iterate through the dirs you're interested in, and avoid temporary files:

for d in $(find $1 -type d -name '2010') ; do

Then you can use basename and dirname to extract parts of that directory name and reconstruct the desired one. Something like:

  b="$(dirname $d)"
  p="$(basename $b)"
  echo mv "$d" "$b/$p" 

You could use shell string replace operations instead of basename/dirname.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • No need to arrays and awk? you mean I remove the script and do your steps? could you possibly put the whole script? I don't have linux machine now...Thanks – MLSC Apr 13 '14 at 07:53
  • I know my friend but the result just print `mv etc etc` should I remove `echo`? – MLSC Apr 13 '14 at 07:57
  • 1
    You shouldn't remove the echo until you've tested it and verified that it worked. – Mat Apr 13 '14 at 07:58
  • Excellent...very good answer...I removed echo then it works on my friends machine... – MLSC Apr 13 '14 at 07:59
  • 1
    Never do a for loop like `for d in $(find...); do ... done` on dir/file names as it'll fail when they contain spaces. Always use `find ... | while IFS= read -r d; do ... done` instead. That still has issues when they contain newlines but that's far less likely and if it occurs switch to `find -print0 | xargs -0`. – Ed Morton Apr 13 '14 at 15:56
  • What do you mean by `it'll fail when they contain spaces`? Thanks – MLSC Apr 15 '14 at 06:37
  • @MortezaLSC: what I wrote is unsafe if the paths contain spaces (or newlines, or tabs, etc.). If you're sure that won't ever happen, then it's fine. Otherwise devnull's or Ed Morton's answers are better. – Mat Apr 15 '14 at 07:03
1

This should be close:

find "$1" -type d -name 2010 -print |
while IFS= read -r dir
do
    parentPath=$(dirname "$dir")
    parentDir=$(basename "$parentPath")
    echo mv "$dir" "$parentPath/$parentDir"
done

Remove the echo after testing. If your dir names can contain newlines then look into the -print0 option for find, and the -0 option for xargs.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185