My issue: I need to copy log files, all with identical names, but stored 1-deep in subdirectories, and change their names.

I'm copying from the a folder called Logfiles which contains a bunch of folders:

W3SVC114, W3SVC1507562355, W3SVC350179472, etc.

Each of these folders will contain a file named: u_ex[YYMMDD].log, where [YYMMDD] is a datestamp.

I need all of these logfiles in one folder. Since all names are identical I would like to add the directory name to the resulting file name, for example:

W3SVC1507562355/u_ex150407.log becomes W3SVC1507562355_u_ex150407.log

How do I make all of these happen? I'm a bit out of my depth here... :-/

  • Are we 'talking' Windows or Linux/Unix here?
    – Lambert
    Apr 7, 2015 at 8:46

4 Answers 4


Zsh comes with a function called zmv that makes it easy to move or copy files and apply pattern-based transformations on the name. Put this in your .zshrc (or run it on the command line):

autoload -U zmv
alias zcp='zmv -C'
alias zln='zmv -L'

Then your copy-with-renaming can be done with any of the following equivalent commands:

zcp 'Logfiles/(*)/(*.log)' 'destination_directory/${1}_$2'
zcp -w 'Logfiles/*/*.log' 'destination_directory/${1}_${2}.log'
zcp -W 'Logfiles/*/*.log' 'destination_directory/*_*.log'

If you don't want to install zsh, you can do the same thing with a loop in any shell:

cd Logfiles
for x in */*.log; do
  cp -- "$x" "destination_directory/${x%/*}_${x##*/}"

You can use following script to copy files from one location to another with modified name.

Note: In following script we have hard-coded two values.

  1. /Logfiles/ :- change Logfiles name to valid folder name from which you have to copy files.

  2. /tmp/ :- It is a directory under which you want to copy files. Change this directory name according to your requirements.

    find /Logfiles/ -maxdepth 1  -type f |  #find all files located under folder Logfiles with maxdepth one.
    while read FILEDIR                          #Read all files line by line.
       DIR="${FILEDIR%/*}"                   # Get the folder name its inside
    #       echo $DIR
       FILE="${FILEDIR/*\/}"                 # Get the plain file name.
    #    echo $FILE
       NEWFILE="${DIR}"_"${FILE}"           # set new filename.
    #       echo $NEWFILE
       echo -e "coping $FILE from $DIR in /tmp with name $NEWFILE \n"
      cp $DIR/$FILE /tmp/$NEWFILE     #copy file from old location to new location with modified name.           
  • @Evert Meulie Please mark answer as correct if you find solution useful.
    – AVJ
    Apr 7, 2015 at 14:40
  • 1
    Using find here even though no recursion is wanted is overkill and overcomplication. At least put double quotes around variable substitutions and use IFS= read -r to avoid gratuitously breaking on file names with spaces and other special characters Apr 7, 2015 at 23:43
  • @Gilles Thanks for your inputs. Those are really helpful.
    – AVJ
    Apr 8, 2015 at 8:47

With pax:

pax -'rws|/|_|' -- */u_ex150407.log target/dir

pax is the standard file-archiver specified by POSIX. Unfortunately - though it is required in the Linux Standard Base and has been for a few version increments of same - for whatever reason, many distribtions do not package it with the default installation as both standards require. I consider this a shame, because it is a very versatile tool.

Above I tell pax to go into -read and -write mode (which translates to a copy) and - when naming its output files - to -substitute the first / in any of its named copy file parameters with a _. You can basically do standard BRE sed syntax there (except that literal newlines in the left-hand-side are permissible here), but there's no need for anything elaborate in this case.

Anyway, that's all you need. If you don't have it installed for some reason, I recommend you get it and give pax a try.


Plain POSIX shell answer:

for i in */*.log
do mv "$i" "${i//\//_}"

moves every file matching */*.log to the same name with / substituted by _.

  • And if you want to see what it's moving, just add -v to the mv command. May 5, 2015 at 16:49

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.