سؤال

I would like to use the stat command inside awk to achieve a modification time in seconds of listed files. I want to keep the output information from stat in a variable and further process inside awk. How to format the command to achieve this objective?

ls -la | awk '{ system("a=$(stat -c %Y $9)");    (further operation on a...)  }'

Thanks in advance

Dominik

هل كانت مفيدة؟

المحلول

bash has no stat command. bash is a shell, an application whose primary goal is to run other commands and make them interact together.

stat is the name of a few different applications, with different syntax whose primary goal is to be an interface to the stat(2) system call, that is to get and output metadata information about a file.

The one you seem to be referring to seems to be GNU stat. zsh is the only shell to my knowledge that has a builtin stat command (with different syntax).

awk is yet another application, an interpreter for the awk language, whose primary goal is to do text processing. The awk language has a system() function that's used to run a shell (sh, not bash) command line.

With:

awk '{system("a=$(stat -c %Y $9)")}'

awk starts a new process that executes a sh interpreter. That shell sets its own a variable to the output of stat and then exits. So, that's not useful. What you want is set an awk variable.

You'll do that with awk's equivalent of the shell's command subtitution ($(...)):

awk '{"stat -c %Y " $9  | getline a; ...}'

However, there, awk's 9th field ends up being expanded and included in the code passed to the shell that interprets that stat... command line, so it becomes a code injection vulnerability. For instance if $9 is x;reboot (a perfectly valid file name), the command line becomes stat -c %Y x;reboot and that will run the reboot command.

Now, note that GNU ls can output the unix time by itself.

ls -l --time-style=+%s

Or you could also use GNU find to get something that is reliably parseable:

find . ! -name . -prune -printf '%Ts/%s/%p\0' |
  while IFS=/ read -d '' -r mtime size name; do
    something with "$mtime" "$size" "$name"
  done

(here using / as the delimiter as it's the only character guaranteed not to be found at the end of the paths as output by find)

find will also get you sub-second granularity where available with %T@ instead of %Ts.

نصائح أخرى

awk '{ "stat -c %Y " $9 | getline a; stuff_with_a; }'

If you don't need awk, you could always use

find $(pwd) -exec stat \{} --printf="%y\n" \;

Small addition to what was said. When having a large number of files:

awk '{ fh="stat -c %Y " $9; fh | getline a; close(fh); stuff_with_a; }'

Otherwise you hit "too many files open".

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top