1

l have about 100 directories such as :

  • walking,
  • writing,
  • dancing,
  • swimming.

Each of these directories contains a set of files.

l would like to add the prefix name of the directory to the filenames of its files.

For instance:

writing :
0ZPQl5QUvo0_000202_000212.mp4  
AFV8x8ezN8g_000016_000026.mp4  
-HutuMqTAPw_000275_000285.mp4 
qtvsw6h3yQo_000228_000238.mp4  
Ub0rc6U6nfI_000100_000110.mp4

becomes :

writing :
writing_0ZPQl5QUvo0_000202_000212.mp4  
writing_AFV8x8ezN8g_000016_000026.mp4  
writing_-HutuMqTAPw_000275_000285.mp4 
writing_qtvsw6h3yQo_000228_000238.mp4  
writing_Ub0rc6U6nfI_000100_000110.mp4

How can I do that?

2

4 Answers 4

4

Here's a slightly improved version of your script - the main differences are

  • using a shell glob * in place of $(ls) - see Bash Pitfall #1

  • quoting any variable expansions (allows filenames with whitespace or other funny characters - see Bash Pitfall #2)

  • marking the end of options to mv using the -- GNU extension - this lets it handle filenames that start with hyphens as well

So

for d in *; do 
  [[ -d "$d" ]] && cd "$d" || continue
  for f in *.mp4; do 
    echo mv -v -- "${f}" "${d}_${f}"
  done
  cd -
done

Or, more portably, you can loop over ./*.mp4 to protect from leading hyphens - but then you have to strip it off during the mv

for d in *; do 
  [ -d "$d" ] && cd "$d" || continue
  for f in ./*.mp4; do 
    echo mv -v "${f}" "${d}_${f#./}"
  done
  cd -
done

In either case, remove the echo (and the -v if you wish) once you are sure that it's working how you expect.

1

The problem is solved using the following script :

for i in $(ls); do                                                 
  if [ -d $i ]; then                      
     fname=${i##*/}                 
     echo $fname                           
     cd $i                                       
     for z in *.mp4; do               
       echo $z  
       cp $z ${fname}_${z}
       rm $z                   
     done                                        
     cd ..                                         
  fi                                              
done
2
  • Bash Pitfall #1, Bash Pitfall #2 Jan 23, 2018 at 13:44
  • @steeldriver, the problem with this solution, it doesn't add prefix directory to files starting with '-' and doesn't process directories containing space such as the following directory 'walking road'
    – Joseph
    Jan 23, 2018 at 13:59
0

Assuming you are in the directory containing all these directories dancing, writing, etc, the command

for folder in $(find -mindepth 1 -type d); do
  cd $folder
  PRE=${folder#./}
  for file in *; do
    mv "$file" "${PRE}_$file"
  done
  cd ..
done

will achieve what you want. I've tested it, and it worked even when the filenames contained spaces or newlines. It didn't work with such characters in the folder names, though, for example walking slowly.

Edit: The previous code does not handle spaces or newlines in folder names. To cover that, use the modified code

for folder in *; do
  if [ -d "$folder" ]; then
    cd "$folder"
    PRE=${folder#./}
    for file in *; do
      mv "$file" "${PRE}_$file"
    done
    cd ..
  fi
done

Edit 2: If a filename starts with a - (dash), the command may interpret it as an option. To deal with leading dashes, insert a -- between the mv command and its arguments. This tells mv to stop scanning for options.

So the final code is

for folder in *; do
  if [ -d "$folder" ]; then
    cd "$folder"
    for file in *; do
      mv -- "$file" "${folder}_$file"
    done
    cd ..
  fi
done
5
  • @Stephan, thank you for you answer. However , it adds 'have_' to folder names and doesn't add prefix directory to files starting with '-' .
    – Joseph
    Jan 23, 2018 at 13:56
  • @Joseph: Replace the firsts line by for folder in *; do and surround the body of the for loop with an if [ -d "$folder" ] statement, just as you did in your answer. That should take care of the spaces in folder names. Jan 23, 2018 at 14:21
  • The problem with your solution, it's that it doesn't process only the current directory but from '/' root
    – Joseph
    Jan 23, 2018 at 14:26
  • @Joseph: I forgot to use double quotes in the cd statement. I really recommend reading sleeldriver's linked pages. Jan 23, 2018 at 14:46
  • @Joseph: I appended a solution for how to deal with leading dashes. Jan 23, 2018 at 15:13
0

Use find and prename:

find DIR... -mindepth 1 -type f | prename -n 's/([^\/]+)\/([^\/]+)$/$1\/$1_$2/'

Remove the -n option to actually rename the files and not just print how files would be renamed.

You must log in to answer this question.

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