4

I'm currently taking a class for Operating Systems and we're learning to do bash scripts as part of the curriculum. I need to append the date to all the files in a directory without touching sub-directories via a script. I've been to cobble up a one-liner script that will append the date to all the files, but it hits the folders in the current directory as well.

for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done

This'll append the date to the end of the filename, but like I said, it hits the directories under it. I'm currently using version 4.1.2 of bash on RedHatLinux.

I'm confused as all get out because of how inexeperienced with Unix I am (I'm primarily a Windows user), so any help would be appreciated.

4
  • 2
    You need to limit this to only files. Perhaps a if/then test to see if $f is a file or directory? – slm Nov 30 '14 at 3:59
  • With that bash version number you might be vulnerable to shellshock – Anthon Nov 30 '14 at 6:29
  • This would be relatively easy using a one line find command you realize which could be used in a bash script. – mdpc Nov 30 '14 at 7:03
  • @Anthon I'm technically remoting in via Telnet through Putty to the server at my school. We've got one hell of a paranoid Admin who runs the server. – coraldayton Dec 1 '14 at 7:08
4

As slm already indicated you can test for $f to be a regular file. While learning I would change the script to not be a one liner, they tend to be harder to read and maintain:

for f in *
do 
  if [ -f "$f" ]
  then
    mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"
  fi 
done

(you can always fold this later by inserting ; and deleting newlines)

The -f tests the argument to be a regular file (not a device or directory), there are other tests as well (-d for directory e.g, so you could test if [ ! -d "$f" ] as well in this case).

3
  • $(stat -c %Y "$f" | date +%Y%m%d) do the same jobs twice. %Y(as and %y) is the file's last modification time. So it is useful to receive it from date directly: mv -- "$f" "f-$(date +%Y%m%d -r "$f") – Costas Nov 30 '14 at 11:15
  • @Costas I didn't really look at that part of the problem, only at the application of the mv on the OPs directories. You might want to post that comment on the Q or the OP might not see that. – Anthon Nov 30 '14 at 11:20
  • Certanly, I agree, it is not a problem but code will looks better. – Costas Nov 30 '14 at 11:28
2

This should work for what you require;

for file in $(find . -type f); do mv -- "$file" "$file-$(stat -c %Y "$file" | date +%Y%m%d)"; done

The explain the new part, you're using the find command to only find files (type -f);

find . -type f.

3
  • This will change file names in subdirectories as well. – Anthon Nov 30 '14 at 6:32
  • It will also fail for filenames with spaces/other special chars. Pipe to a while loop instead: find . -type f -maxdepth 1 -print0 | while IFS= read -r -d $'\0' file; do ... done – user000001 Nov 30 '14 at 8:24
  • This solution will fail for a large number of files returned from the find. – Be Kind To New Users Nov 30 '14 at 16:08
1

You don't need a loop at all, just use find together with exec option + sh -c:

find . -maxdepth 1 -type f -exec sh -c 'mv -- "$0" "$0"-$(stat -c %Y "$0" | date +%Y%m%d)' {} \;

However piping stat to date doesn't make much sense to me. If you want to append current date to all filenames then stat is not needed at all:

find . -maxdepth 1 -type f -exec sh -c 'mv -- "$0" "$0"-$(date +%Y%m%d)' {} \;

On the other hand if you want to append time of last modification of each file then use -r option of the date:

find . -maxdepth 1 -type f -exec sh -c 'mv -- "$0" "$0"-$(date -r "$0" +%Y%m%d)' {} \;

And if you want to, just for exercise, use output from stat as an input of the date, then use --date option of date command:

find . -maxdepth 1 -type f -exec sh -c 'mv -- "$0" "$0"-$(date +%Y%m%d --date=@$(stat -c %Y "$0"))' {} \;

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.