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
    Commented Nov 30, 2014 at 3:59
  • With that bash version number you might be vulnerable to shellshock
    – Anthon
    Commented Nov 30, 2014 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
    Commented Nov 30, 2014 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. Commented Dec 1, 2014 at 7:08

3 Answers 3

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
    Commented Nov 30, 2014 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
    Commented Nov 30, 2014 at 11:20
  • Certanly, I agree, it is not a problem but code will looks better.
    – Costas
    Commented Nov 30, 2014 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
    Commented Nov 30, 2014 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
    Commented Nov 30, 2014 at 8:24
  • This solution will fail for a large number of files returned from the find. Commented Nov 30, 2014 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"))' {} \;

You must log in to answer this question.

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