Czy są jakieś alternatywy dla polecenia `find` w systemie Linux dla SunOS?

10

findPoleceń w systemie Linux ma wiele opcji w porównaniu z findpoleceniem na SunOS lub Solaris.

Chcę użyć findpolecenia w następujący sposób:

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

Działa idealnie na komputerze z systemem Linux, ale to samo polecenie nie ma opcji -printfna komputerze z systemem SunOS. Chcę dostosować dane wyjściowe w "%TY-%Tm-%Td %f\n"formacie.

Proszę sugerować wszelkie alternatywy dla SunOS.

Pratik Mayekar
źródło
5
Aby korzystać z GNU findw systemie Solaris, zainstaluj pakiet findutils .
Kusalananda

Odpowiedzi:

21

Zauważ, że nie ma to nic wspólnego z Linuksem; ten -printfpredykat jest specyficzny dla implementacji GNU find. Linux nie jest systemem operacyjnym, to tylko jądro występujące w wielu systemach operacyjnych. Podczas gdy większość tych systemów operacyjnych korzystała kiedyś z przestrzeni użytkownika GNU, teraz ogromna większość systemów operacyjnych korzystających z Linuksa jest osadzona i ma podstawowe polecenia, jeśli takie mają.

Komenda GNU find, która poprzedza Linuksa, może być zainstalowana na większości systemów operacyjnych uniksopodobnych. Z pewnością był używany w systemie Solaris (wtedy zwanym SunOS), zanim pojawił się Linux.

Obecnie jest nawet dostępny jako pakiet Oracle dla Solaris. W file/gnu-findutilssystemie Solaris 11 jest to włączone , a polecenie ma nazwę gfind(dla GNU find, aby odróżnić je od polecenia systemu find).

Teraz, jeśli nie możesz zainstalować pakietów, najlepszym rozwiązaniem jest prawdopodobnie użycie 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

Nadal używamy find(implementacja Solaris), aby znaleźć pliki, ale używamy jego -execpredykatu, aby przekazać listę plików perl. I perlrobi lstat()na każdym, aby pobrać metadane pliku (w tym czas modyfikacji jako 10. element ( $s[9])), interpretuje go w lokalnej strefie czasowej ( localtime()) i formatuje go ( strftime()), który następnie wyświetla printobok nazwy pliku ( $_jest zmienną pętli, jeśli żaden nie jest podany perli $!jest odpowiednikiem stderror(errno)tekstu błędu dla ostatniego niepowodzenia wywołania systemowego).

Stéphane Chazelas
źródło
Czy nie byłoby miło, gdyby ludzie GNU spojrzeli na istniejące standardy przed wdrożeniem ulepszeń? Istnieje już standard, w jaki sposób używać formatu do określania lsdanych wyjściowych typu, patrz Specyfikacja trybu listy w pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
schily
5
@schily, GNU find„s -printfwyprzedza POSIX.2, więc ludzie są winni POSIX tutaj. Zauważ też, że specyfikacja POSIX była publiczna dopiero w 2000 roku. Nadal winiłbym ludzi GNU za wprowadzenie ich statponad dekadę później za pomocą innej i gorszej składni dla specyfikacji formatu.
Stéphane Chazelas,
Czy możesz wspomnieć, kiedy GNU find dodał tę funkcję? Ponieważ system Solaris pax obsługuje ten tryb listy od 1998 r., Myślę, że został wprowadzony z SUSv2.
schily
1
Możesz także po prostu zainstalować program GNU Find we własnym katalogu bin i ustawić ścieżkę wyszukiwania tego przed katalogami kanonicznymi.
Peter - Przywróć Monikę
@schily, najwcześniejsza wersja GNU znajduję, że mam 3.1 z 1991 roku, już miała -printf (3.1 dodała dyrektywę formatu% k), dziennik zmian nie wspomina, kiedy został dodany, być może był tam od samego początku. Dziennik zmian pochodzi z 1987 r.
Stéphane Chazelas,
0

Innym sposobem podejścia jest find2perlskrypt, który konwertuje (tutaj podzbiór) findpolecenia na odpowiedni skrypt perla. Skrypt perla używa File::Findmodułu do ciężkiego podnoszenia. Ponieważ skrypt find2perl w moim systemie nie obsługiwał -printfpredykatu, dodałem go ręcznie:

#! /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;

W dwóch przykładowych plikach, które utworzyłem, dane wyjściowe są takie same:

$ 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
źródło