19

I am trying to update the timestamps of all folders in the cwd using this:

for file in `ls`; do touch $file; done

But it doesn't seem to work. Any ideas why?

Bernhard
  • 11,992
  • 4
  • 59
  • 69
javamonkey79
  • 369
  • 2
  • 3
  • 11

6 Answers6

28

All the answers so far (as well as your example in the question) assume that you want to touch everything in the directory, even though you said "touch all folders". If it turns out the directory contains files and folders and you only want to update the folders, you can use find:

$ find . -maxdepth 1 -mindepth 1 -type d -exec touch {} +

Or if your find implementation doesn't support the non-standard -mindepth/-maxdepth predicates:

$ find . ! -name . -prune -type d -exec touch {} +

This:

$ touch -c -- */

Should work in most shells except that:

  • it will also touch symlinks to directories in addition to plain directories
  • it will omit hidden ones
  • if there's no directory or symlink to directory, it would create a file called * in shells other than csh, tcsh, zsh, fish or the Thompson shell (which would report an error instead). Here, we're using -c to work around it, though that could still touch a non-directory file called *.

With zsh, to touch directories only, including hidden ones:

touch -- *(D/)
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
Michael Mrozek
  • 91,316
  • 38
  • 238
  • 232
12

Try

touch ./*

It avoids the unnecessary for loop which would spawn a new process for every single file and works for all file names, even ones with spaces or ones that look like options (like -t). The only time it wouldn't work is if you have no (non-dot) files in the directory in which case you would end up creating a file named *. To avoid that, for the specific case of touch most implementations have a -c option (also called --no-create in GNU versions) to not create nonexistent files, i.e.

touch -c ./*

See also the good references in jasonwryan's answer as well as this one.

jw013
  • 50,274
  • 9
  • 137
  • 141
  • 1
    What will happen if you have 1 million folders in the cwd? – Steven Monday Oct 08 '11 at 02:54
  • If you run into "argument list too long" type problems it's probably best to switch to "heavier" tools like `find . -type d -maxdepth1 -print0 | xargs -0 touch`, or MichaelMrozek's [answer](http://unix.stackexchange.com/questions/22291/touch-all-folders-in-a-directory/22298#22298) above. – jw013 Oct 08 '11 at 03:02
7

You shouldn't attempt to parse the output of ls.

Also, you should quote your "$file" to capture any whitespace. See http://www.grymoire.com/Unix/Quote.html

Something like this might achieve what you are after:

for file in *; do touch "$file"; done

See the first two Bash Pitfalls for a more thorough explanation.

jasonwryan
  • 71,734
  • 34
  • 193
  • 226
  • 2
    Close but not quite. A `touch ./*` should work in most cases. There really is no need for the `for` loop since `touch` can take multiple files, and you need the `./` to handle files with names like `--help` properly. This is a good [resource](http://www.dwheeler.com/essays/filenames-in-shell.html) on the subject. – jw013 Oct 08 '11 at 00:32
  • Why does '*' work? – javamonkey79 Oct 08 '11 at 00:33
  • @javamonkey79 It's shell [globbing](http://mywiki.wooledge.org/glob). – jw013 Oct 08 '11 at 00:35
  • 1
    @jw013 Excellent point: and thank you for the wheeler link. – jasonwryan Oct 08 '11 at 00:48
  • Note that `*` does not capture files and directories whose name begins with a dot. One way to fix that is to enable the `dotglob` shell option via `shopt -s dotglob`. – Witiko Aug 30 '16 at 15:49
  • `ls` can be parsed like any other command. Discouraging parsing it is as senseless as it is unnecessary. The linked article should be rewritten as 'Caveats when parsing ls'. – slashmais May 28 '17 at 09:34
0

Just in case you wanted to update the timestamps for all files/directories that descend from that directory try either (note my find here below is an alias for what some systems call gfind, i.e., the gnu version of find).

 find ./ -exec touch -am '{}' \;

Or, more efficiently,

 for f in **; do touch -am $f; done 

The -am means update both access and modification. Note you likely can't just do touch -am ** since you can't run an exec on a list that exceeds getconf ARG_MAX

Peter Gerdes
  • 131
  • 5
0
find . -maxdepth 8 -mindepth 1 -type d -exec touch {} +

What are mindepth and maxdepth levels?

maxdepth levels : Descend at most levels (a non-negative integer) levels of directories below the starting-points. -maxdepth 0 means only apply the tests and actions to the starting-points themselves.

mindepth levels : Do not apply any tests or actions at levels less than levels (a non-negative integer). -mindepth 1 means process all files except the starting-points.

Generally, we don't have directories with depth more than 8. Hence is the above command, I have kept the maxdepth as 8.

  • Why `-maxdepth 8`? [Brevity is acceptable, but fuller explanations are better](https://unix.stackexchange.com/help/how-to-answer). – Kusalananda Aug 01 '21 at 06:07
-1
for file in `find .`; do touch $file; done
HalosGhost
  • 4,732
  • 10
  • 33
  • 41