3

I am looking at the touch command line utility (on Linux), and from the examples I found in tutorials, I see how one can bump the access or modification timestamp to a specified time, the current time, or to a reference file.

However, I would like to do the following: The relative age of my files (relative to each other) has information valuable to me, and I'd rather not lose that. But I need each file in (recursive) folders look a few months younger than they are. So each file could refer to itself, bump the time, but apply this to each file in a tree of folders. What is a good way to do this?

#!/bin/bash
FILES=$(find $HIGHEST_FOLDER -type f -name *.*)
for f in $FILES
do
  touch -ram f -F 7776000 f
  # bumping access and modification timestamps by 3 months?
done

Or am I better off using find -exec as suggested in this answer? (There are many files in these folders.) How could that work?

László
  • 193

3 Answers3

3

Assuming your are on a Linux system, or at least that you have GNU touch and GNU date, you can do (in bash; zsh is the same but does not need the shopt globstar):

$ shopt globstar
$ for f in **; do 
    touch -d "$(date -d "$(stat -c '%y' "$f") +3 months")" "$f"
  done

That, however, will ignore hidden files. To match those as well, run shopt -s dotglob before the above commands.

Explanation

  • shopt -s globstar : This sets bash's globstar option which means that ** will match all files and zero or more directories and subdirectories.
  • shopt -s dotglob: makes * (and **) also match files whose names begins with a ..
  • for f in **; do ...; done : iterate over all files and directories, saving them as $f.
  • stat -c '%y' "$f" : this is the current time stamp of the current file or directory.
  • date -d $(...) +3 months : print the date that is three months after the given string (in this case, that string is the output of the stat command on $f).

All together, the above will find the modification date of each file or directory in the current folder (including all subdirectories) and set its date three months after whatever it is now.

terdon
  • 242,166
1

I would use the -exec of find - a oneliner.

find $HIGHEST_FOLDER -type f -name '*.*' -exec touch -d "$(date -d "$(stat -c '%y' {}) +3 months")" {} \;

Quote *.*, otherwise find will take filenames from the current directory and fail.

Finally, you MUST specify \;, backslash followed by semi-colon, -exec mandates this. the {} is the current file find found.

There is no -F switch to GNU touch, so your example does not work. There are also multiple syntax issues:

In your for loop above, you need to change f to $f:

touch [...] $f

Otherwise it will look for a file named f in the current directory and change its date x times, where x is the number of files under $HIGHEST_FOLDER.

If you stick to sub shell ($(...) before your loop), you must make sure that $HIGHEST_FOLDER is set in the sub shell.

thecarpy
  • 3,935
  • 1
    What system is this on? Neither GNU coreutils nor FreeBSD supports touch -F to make a relative change to a timestamp. The whole point of the question is how to make that change. – Gilles 'SO- stop being evil' Jan 31 '15 at 21:54
  • 1
    Indeed, I meant to fix the op's syntax ... I should have probably looked up the man page for touch; I was assuming op had already done that. Editing answer with find variant which I think is better (it includes dot files). – thecarpy Feb 02 '15 at 07:00
  • @thecarpy I just tried this. I am getting a stat: cannot stat `{}': No such file or directory message. – László Mar 01 '15 at 21:03
1

From the description of the problem I believe you are looking for the tool which can get time of last file modification and then add 3 months to it. You can do it with stat + touch + some shell arithmetic evaluation. For example to add 90 days to file timestamp you can write

touch -d "@$(( $(stat -c '%Y' file) + 90*24*3600 ))" file

Then just loop over all files you need to.

jimmij
  • 47,140