¿Hay alguna alternativa al comando `find` en linux para SunOS?

10

El findcomando en Linux tiene muchas opciones en comparación con el findcomando en SunOS o Solaris.

Quiero usar el findcomando así:

find data/ -type f -name "temp*" -printf "%TY-%Tm-%Td %f\n" | sort -r

Funciona perfectamente bien en una máquina Linux, pero el mismo comando no tiene la opción -printfen una máquina SunOS. Quiero personalizar mi salida en el "%TY-%Tm-%Td %f\n"formato.

Por favor, sugiera cualquier alternativa para SunOS.

Pratik Mayekar
fuente
55
Para usar GNU finden Solaris, instale el paquete findutils .
Kusalananda

Respuestas:

21

Tenga en cuenta que no tiene nada que ver con Linux; ese -printfpredicado es específico para la implementación de GNU de find. Linux no es un sistema operativo, es solo el núcleo que se encuentra en varios sistemas operativos. Si bien la mayoría de esos sistemas operativos solían usar una tierra de usuarios de GNU en el pasado, ahora la gran mayoría de los sistemas operativos que usan Linux están integrados y tienen comandos básicos si los tienen.

El findcomando GNU , anterior a Linux, se puede instalar en la mayoría de los sistemas operativos tipo Unix. Ciertamente se usó en Solaris (llamado SunOS en aquel entonces) antes de que saliera Linux.

Hoy en día, incluso está disponible como un paquete de Oracle para Solaris. En Solaris 11, eso está dentro file/gnu-findutils, y el comando se nombra gfind(para GNU find, para distinguirlo del propio findcomando del sistema ).

Ahora, si no puede instalar paquetes, su mejor opción es usar perl:

find data/ -type f -name "temp*" -exec perl -MPOSIX -le '
  for (@ARGV) {
    unless(@s = lstat($_)) {
      warn "$_: $!\n";
      next;
    }
    print strftime("%Y-%m-%d", localtime($s[9])) . " $_";
  }' {} + | sort -r

Aquí, todavía estamos usando find(implementación de Solaris) para encontrar los archivos, pero estamos usando su -execpredicado para pasarle la lista de archivos perl. Y perlhace una lstat()en cada uno para recuperar los metadatos del archivo (incluida la hora de modificación como el décimo elemento ( $s[9])), lo interpreta en la zona horaria local ( localtime()) y lo formatea ( strftime()), que luego se encuentra printjunto al nombre del archivo ( $_es la variable del bucle si none se especifica en perl, y $!es el equivalente del stderror(errno)texto de error para la última falla de la llamada al sistema).

Stéphane Chazelas
fuente
¿No sería bueno si la gente de GNU observara los estándares existentes antes de implementar mejoras? Ya existe un estándar sobre cómo usar un formato para especificar la lssalida de tipo, vea la especificación del modo de Lista en pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
schily
55
@schily, GNU findes -printfanterior a POSIX.2, por lo que la gente de POSIX tiene la culpa aquí. También tenga en cuenta que la especificación POSIX no era pública hasta la década de 2000. Todavía culpo a la gente de GNU por presentar su statmás de una década más tarde con una sintaxis diferente e inferior para su especificación de formato.
Stéphane Chazelas
¿Podría mencionar cuándo GNU find agregó esa característica? Como Solaris pax admite este modo de lista desde 1998, supongo que se ha introducido con SUSv2.
schily
1
También puede simplemente instalar un gnu find en su propio directorio bin y establecer la ruta para buscar antes de los directorios canónicos.
Peter - Restablece a Monica el
@schily, la primera versión de GNU find que tengo es 3.1 de 1991, ya tenía -printf (3.1 agregó la directiva de formato% k), el registro de cambios no menciona cuándo se agregó, posiblemente estuvo allí desde el principio. El ChangeLog se remonta a 1987.
Stéphane Chazelas
0

Otra forma de abordarlo es con el find2perlscript, que convierte (aquí, un subconjunto) de un findcomando en un script perl correspondiente. El script perl usa un File::Findmódulo para hacer el trabajo pesado. Debido a que el script find2perl en mi sistema no era compatible con el -printfpredicado, lo agregué manualmente:

#! /usr/bin/perl -w

use strict;
use File::Find ();

use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

sub wanted {
    my ($dev,$ino,$mode,$nlink,$uid,$gid, $mtime, $year, $month, $day);

    if ((($dev,$ino,$mode,$nlink,$uid,$gid,undef,undef,undef,$mtime) = lstat($_)) &&
    -f _ &&
    /^temp.*\z/s) {
        (undef, undef, undef, $day, $month, $year) = localtime($mtime);
        $year += 1900;
        $month++;
        printf "%d-%d-%d %s\n", $year, $month, $day, $_;
    }
}

File::Find::find({wanted => \&wanted}, 'data/');
exit;

En dos archivos de muestra que creé, el resultado es el mismo:

$ tree data
data
├── subdir
   └── foo
       └── temp2
└── temp1

2 directories, 2 files

$ touch -d 2018-06-20 data/subdir/foo/temp2
$ touch -d 2018-05-19 data/temp1

$ find data/ -type f -name "temp*" -printf "%TY-%Tm-%Td %f\n" | sort -r
2018-06-20 temp2
2018-05-19 temp1

$ ./perlfind | sort -r
2018-06-20 temp2
2018-05-19 temp1
Jeff Schaller
fuente