Есть ли альтернативы команде `find` в Linux для SunOS?

10

Команда findв Linux имеет много опций по сравнению с findкомандой в SunOS или Solaris.

Я хочу использовать findкоманду следующим образом:

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

Он отлично работает на Linux-машине, но та же команда не имеет опции -printfна SunOS-машине. Я хочу настроить вывод в "%TY-%Tm-%Td %f\n"формате.

Пожалуйста, предложите любые альтернативы для SunOS.

Пратик Майекар
источник
5
Чтобы использовать GNU findв Solaris, установите пакет findutils .
Кусалананда

Ответы:

21

Обратите внимание, что это не имеет ничего общего с Linux; этот -printfпредикат специфичен для реализации GNU find. Linux - это не ОС, это просто ядро, найденное во многих ОС. Хотя в прошлом большинство из этих ОС использовали пользовательское пространство GNU, в настоящее время подавляющее большинство ОС, использующих Linux, являются встроенными и имеют базовые команды, если они есть.

Команда GNU find, предшествующая Linux, может быть установлена ​​в большинстве Unix-подобных ОС. Он, безусловно, использовался в Solaris (тогда назывался SunOS) до выхода Linux.

В настоящее время он даже доступен в виде пакета Oracle для Solaris. На Solaris 11 он есть file/gnu-findutils, и команда названа gfind(для GNU find, чтобы отличить ее от собственной findкоманды системы).

Теперь, если вы не можете установить пакеты, вам лучше всего использовать 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

Здесь мы все еще используем find(реализация Solaris) для поиска файлов, но мы используем его -execпредикат для передачи списка файлов perl. И perlвыполняет для lstat()каждого метаданные файла (включая время изменения как 10-й элемент ( $s[9])), интерпретирует его в местном часовом поясе ( localtime()) и форматирует его ( strftime()), который затем printотображается вместе с именем файла ( $_это переменная цикла, если ни один из них не указан perlи не $!является эквивалентом stderror(errno)текста ошибки для последнего сбоя системного вызова).

Стефан Шазелас
источник
Разве не было бы хорошо, если бы люди GNU смотрели на существующие стандарты до внедрения улучшений? Уже существует стандарт того, как использовать формат для указания lsтипа вывода, см. Спецификацию режима списка в pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
schily
5
@schily, GNU find«s -printfпредшествует POSIX.2, так что люди POSIX виноваты здесь. Также обратите внимание, что спецификация POSIX не была общедоступной до 2000-х годов. Я по-прежнему виню людей GNU за то, что они представили их statболее десяти лет спустя с другим и худшим синтаксисом для его спецификации формата.
Стефан Шазелас
Не могли бы вы упомянуть, когда GNU find добавила эту функцию? Поскольку Solaris pax поддерживает этот режим списка с 1998 года, я полагаю, он был представлен в SUSv2.
Шили
1
Вы также можете просто установить gnu find в свой собственный каталог bin и указать путь для поиска в канонических каталогах.
Питер - Восстановить Монику
@schily, самая ранняя версия GNU, которую я нашел, это 3.1 из 1991 года, в ней уже был -printf (3.1 добавила директиву формата% k), в списке изменений не упоминается, когда он был добавлен, возможно, он был там с самого начала. История изменений восходит к 1987 году.
Стефан Шазелас
0

Другой способ приблизиться к этому - использовать find2perlскрипт, который преобразует (здесь подмножество) findкоманды в соответствующий скрипт perl. Скрипт perl использует File::Findмодуль для выполнения тяжелой работы. Поскольку скрипт find2perl в моей системе не поддерживает -printfпредикат, я добавил его вручную:

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

Для двух примеров файлов, которые я создал, выходные данные одинаковы:

$ 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
Джефф Шаллер
источник