Разница между файлом test -a и файлом test -ef

QNX (Neutrino 6.5.0) использует в качестве оболочки реализацию ksh с открытым исходным кодом. Многие предоставленные сценарии, в том числе сценарии запуска системы, используют такие конструкции, как

if ! test /dev/slog -ef /dev/slog; then
    # do something
fi

чтобы проверить, существует ли менеджер ресурсов в файловой системе. Я искал и смог найти только очень скучные объяснения того, что -ef проверяет, действительно ли два параметра являются одним и тем же файлом. Поскольку указанное имя файла одно и то же, кажется, что оно просто сводится к проверке существования файла.

Я проверил поведение test -a и test -e (оба, кажется, проверяют наличие файла любого типа в соответствии с различными документами, которые я читал), и они, кажется, также работают.

Есть ли разница в проверках между -ef и -a/-e? Является ли использование -ef какой-то попыткой защититься от состояния гонки в существовании файла?


person tinman    schedule 05.07.2012    source источник
comment
Похоже, что это действительно может быть проверка существования файла для двух разных вызовов stat(). Удаляется ли запись /dev драйвером/менеджером (например, после выключения) только в том случае, если кто-то проверяет ее существование?   -  person jhfrontz    schedule 12.07.2012
comment
@jhfrontz: я не совсем уверен, что вы имеете в виду, но (в качестве примера) псевдоустройство /dev/slog удаляется только тогда, когда драйвер убит, что обычно не происходит в середине вызова test, поскольку оно является частью начального сценария запуска системы. В обычном случае /dev/slog процесс может записывать на устройство запись в файл/консоль/память, и, хотя это может закончиться с другим именем файла, устройство, отображаемое в /dev, должно быть таким же, как до напишите в /dev/slog.   -  person tinman    schedule 12.07.2012
comment
Я предполагаю, что stat'ing устройства имеет какой-то побочный эффект (например, побуждает водителя/менеджера выполнить какую-то уборку), например, когда первый вызов stat() (из test) завершен, файл/устройство удален/заменен драйвером, что приводит к тому, что второй stat() получает другую информацию, что, в свою очередь, приводит к сбою test. Я давно не пользовался QNX, но справочная страница slogger предполагает наличие побочных эффектов от взаимодействия с /dev/slog (например, удаление связи приводит к очистке журнала).   -  person jhfrontz    schedule 12.07.2012
comment
Я еще немного покопался - test -a и test -e относительно новые. В какой-то момент они, похоже, не были частью оболочки Posix, которая использовалась QNX (см. qnx.com/developers/docs/qnx_4.25_docs/qnx4/utils/s/sh.html . Так что теперь я подозреваю, что это просто унаследованный узор.   -  person jhfrontz    schedule 24.07.2012
comment
@jhfrontz: Спасибо за ваши усилия, очень информативно и полезно.   -  person tinman    schedule 24.07.2012


Ответы (2)


Просмотр strace на копии Ubuntu Linux ksh не выявил существенных различий. Один звонок stat против двух.

$ strace test /tmp/tmp.geLaoPkXXC -ef /tmp/tmp.geLaoPkXXC

показал это:

mmap(NULL, 7220736, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f11dc80b000
close(3)                                = 0
stat("/tmp/tmp.geLaoPkXXC", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
stat("/tmp/tmp.geLaoPkXXC", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
close(1)                                = 0
close(2)                                = 0

...тогда как

$  strace test -a /tmp/tmp.geLaoPkXXC

показал это:

fstat(3, {st_mode=S_IFREG|0644, st_size=7220736, ...}) = 0
mmap(NULL, 7220736, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f6b49e2b000
close(3)                                = 0
stat("/tmp/tmp.geLaoPkXXC", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
close(1)                                = 0
close(2)                                = 0

Один stat против двух.

$ ksh --version
  version         sh (AT&T Research) 93u 2011-02-08
person Brian Cain    schedule 13.07.2012

Мы не знаем, как код использует статистику именно без кода, нам нужно найти разницу через код.

/* code for -ef */
return (stat (argv[op - 1], &stat_buf) == 0
                  && stat (argv[op + 1], &stat_spare) == 0
                  && stat_buf.st_dev == stat_spare.st_dev
                  && stat_buf.st_ino == stat_spare.st_ino);


/* code for -e/-a */
    case 'a':                   /* file exists in the file system? */
    case 'e':
      return stat (argv[pos - 1], &stat_buf) == 0;

Таким образом, если имена совпадают и два stat() с одинаковыми именами вернут одно и то же значение, то test -a/-e file будет таким же, как test file -ef file. Мы знаем, что первое условие верно, и мы знаем, что второе условие также верно из комментариев от @tinman.

person Lai Jiangshan    schedule 13.07.2012