1

I have a number of directories with titles such as "20150512_101129_3016" and others with additional string following an additional underscore, such as "20150512_101129_3016_v1A" (it's not always v1A, could be v1, or V1a, etc). I would like to rename all directories such that the final string following the final underscore is removed. I'd prefer a solution that looks to remove all text following (and including) the final/3rd underscore since I am uncertain that all directory names will have the same number of characters in the text preceding the 3rd underscore.

2 Answers2

1

You can do this with a simple shell loop:

for x in ./*_*_*_*; do mv -i "$x" "${x%_*}"; done

i.e. for every file whose name contains at least three underscores, rename the file, stripping off the part starting at the last underscore.

If there's a collision (e.g. both 20150512_101129_3016_v1A and 20150512_101129_3016_v1B exist), then the first file in lexicographic order is renamed to the desired target, and the second one is moved to a subdirectory, i.e. 20150512_101129_3016_v1B gets moved to 20150512_101129_3016/20150512_101129_3016_v1B after 20150512_101129_3016_v1A has been renamed to 20150512_101129_3016. To avoid this, add an extra check:

for x in ./*_*_*_*; do
  if [ -e "${x%_*}" ]; then
    echo "Not renaming $x because ${x%_*} already exists"
    continue
  fi
  mv "$x" "${x%_*}"
done

Alternatively, on Linux, pass the -T option to mv to make it do this check.

-1

if the original directory names are homogeneous, i.e. follows the format of XXXXX_XXXX_XXXX (then may be followed by another _ XXXX) this code segment below, should work:

find ./ -maxdepth 1 -type d | while read dir; do
newdir=$(echo ${dir} | cut -d_ -f1-3)
# duplicate directory name protection
if [ -d ${newdir} ]
then 
  newdir=${newdir}_
  echo "duplicate directory encountered. Appending _ to the new dir name"
fi

#did the dir name change ? If not, do nothing
if [ ${newdir} != ${dir} ]
then
  mv ${dir} ${newdir}
fi
done

it assumes you are in the directory which contains these subdirectories.

MelBurslan
  • 6,966
  • 1
    If this is a full tree then your find needs a -depth flag. You should also test to see if $dir and $newdir are different. Also test to see if $newdir already exists (eg if a_b_c_v1 and a_b_c_v1a both exist they'll both try to become a_b_c). – Stephen Harris Aug 15 '16 at 19:08
  • I tried running the most recently edited suggested code in a .sh file and returned: ./suffix.sh: line 11: unexpected EOF while looking for matching }' ./suffix.sh: line 16: syntax error: unexpected end of file – focusbob Aug 15 '16 at 19:30
  • I added a matching } to "newdir" on line 11, then returned: `find: warning: you have specified the -maxdepth option after a non-option argument -type, but options are not positional (-maxdepth affects tests specified before it as well as those specified after it). Please specify options before other arguments.

    duplicate directory encountered. Appending _ to the new dir name mv: cannot move ./' to./_': Device or resource busy`

    – focusbob Aug 15 '16 at 19:32
  • I apologize a } sign went victim to an accidental backspace. Fixed it in the code. Please understand that, the improved code will add an underscore if you happen to have the same directory name with and without a 3rd _ character. I.e., if you have 20150512_101129_3016 and 20150512_101129_3016_V1a, the latter will become 20150512_101129_3016_ to protect the original – MelBurslan Aug 15 '16 at 19:43
  • Thank you. 2 more questions: 1) if I leave in the duplicate directory protection, it appears to also append "" if there is no 3rd underscore, for example 20150512_101129_3016 becomes `20150512_101129_3016. Is there a way to prevent this from happening (as it is not a duplicate)? 2) if I remove the protection, it appears to run fine, but returns:mv: ./' and./.' are the same file. Also, if I have a directory name without a 3rd underscore as per above, I getmv: cannot move ./20150213_123852_3005' to a subdirectory of itself,./20150213_123852_3005/20150213_123852_3005'` – focusbob Aug 15 '16 at 20:10
  • You can remove the first if block if you are sure there will be no duplicate names during processing. 2nd if block is needed to prevent messages like mv: ./' and ./.' are the same file. It doesn't affect the effective outcome but throws out error messages like this, for directories which doesn't have the 3rd _ character in the name. But the second if block doesn't append the _ character by any means – MelBurslan Aug 15 '16 at 20:42
  • Always use double quotes around variable substitutions. And don't use external tools for simple string operations that can be performed in the shell: it's hard to read, difficult to get right, and slow. – Gilles 'SO- stop being evil' Aug 15 '16 at 23:06