I would like to identify files that meet certain string criteria in subdirectories, then rename those files with the final portion of the directory name, 2 directories up ("pd1"?), then I would like to move all of the renamed files to a separate directory.

More detail: say I run the hypothetical code from /x/y/z directory and in that directory are directories with names like '20150416_110508_3006'. The files I'm looking to rename are in (example) '/x/y/z/20150416_110508_3006/dicom', example file name 'o20150416_110508MPRAGESAGs002a1001.nii'. The important elements of the filename needed to differentiate it from like files are the prefix "o", the 's002a' in the middle and the extension ".nii".

I wanted to rename these files with the final portion of the pd1 directory, in this case '3006', so '3006.nii'. Then after doing this for all applicable files, I would like to move the renamed files to a directory in '/x/y/z'.

1 Answer 1


With zsh:

autoload zmv # best in ~/.zshrc
zmv -n '/x/y/z/*_*_(*)/dicom/o*s002a*.nii' '${f:h}/$1.nii'


zmv -n '/x/y/z/*_*_(*)/dicom/o*s002a*.nii' '/x/y/z/somedir/$1.nii'

To move them to somedir in /x/y/z.

Remove the -n to actually do the rename after you're satisfied it does what you want.

zmv would detect conflicting renames prior to starting any of the renames. Doing something similar with other shells like bash would require a longer script. Something like:

#! /bin/bash -
typeset -A seen
shopt -s nullglob
for file in /x/y/z/*_*_*/dicom/o*s002a*.nii; do
  if [[ ${seen[$tag]} ]]; then
    printf >&2 '"%s" and "%s" both map to "%s"\n' "$file" "${seen[$tag]}" "$tag"
    exit 1
for tag in "${!seen[@]}"; do
  echo mv -i -- "${seen[$tag]}" "/x/y/z/somedir/$tag"


(remove the echo to perform the rename).

Note that bash associative arrays (contrary to ksh93 or zsh) have a bug/limitation in that you can't have elements with an empty key. So if you have some foo_bar_/dicom/*.nii files, that won't work properly, so even for that programmatic approach I would still go with zsh or ksh93 instead of bash.

  • I am using bash in redhat, I tried the command 'autoload zmv' but bash returns 'bash: autoload: command not found'.
    – focusbob
    Aug 12, 2016 at 14:21
  • @focusbob, hence the With zsh, and not With bash. zsh is available on RedHat systems as well even if not always installed by default. Aug 12, 2016 at 14:29
  • Thanks, I don't have the ability to install new tools, unfortunately.
    – focusbob
    Aug 12, 2016 at 14:30
  • @focusbob, see edit for a bash4 solution. Note that as long as there's a directory you have write access to and has no execution prevention in place (like /var/tmp or your home directory), you should be able to install zsh there. It's only to install software system-wide that you need superuser privileges. Aug 12, 2016 at 14:53
  • When I run the bash script, I get: './rename.sh: line 2: typeset: -A: invalid option typeset: usage: typeset [-afFirtx] [-p] name[=value] ...' It otherwise appears to work however with 2 remaining issues: 1) I need the renamed files to retain the .nii extension, 2) I learned some folders have additional unnecessary information following an additional underscore. For example, 20150402_143041_3008_V1, and I just want to name the file 3008.nii. Would you please suggest modifications?
    – focusbob
    Aug 12, 2016 at 18:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.