Знайдіть власника каталогу чи файлу, але поверніть лише це та нічого іншого


62

Я шукаю команду, яка поверне власника каталогу і тільки це - наприклад, регулярний вимір, що аналізує ls -latкоманду чи щось подібне? Я хочу використовувати результат в іншому сценарії.

Відповіді:


102

stat з GNU coreutils можуть це зробити:

stat -c '%U' /path/of/file/or/directory

На жаль, існує ряд версій stat, і в їх синтаксисі не так багато узгодженості. Наприклад, на FreeBSD це було б

stat -f '%Su' /path/of/file/or/directory

Якщо портативність викликає занепокоєння, вам, ймовірно, краще скористатися пропозицією Джилла про поєднання lsта awk. Він повинен запустити два процеси замість одного, але має перевагу використання лише стандартних функцій POSIX:

ls -ld /path/of/file/or/directory | awk '{print $3}'

2
stat -c% U / шлях, якщо стислість - це бонус.
tvalvalnder

1
Це передбачає статистику GNU, що не стосується старих систем Linux (навіть у новіших системах я б насторожився, можливо, у домі користувача чи десь у домі користувача може бути інший stat(стандарт для загального сайту) /usr/local/bin), і він рідко доступний про інші уніці.
Жиль

1
stat -c %Uмає перевагу також працювати з BusyBox , якщо statкоманда складена.
Жил,

1
Приємно, останній приклад (ls) працює як на Unix / OSX, так і на Linux
kenorb

1
Зауважте, що ls надрукує uid, якщо немає місцевого користувача, який відповідає власнику (тобто, у мережі), але він stat -c '%U' DIRбуде друкувати UNKNOWN, що є менш корисним або більш доцільним, залежно від того, як ви його переглядаєте.
основні6

18

Розбір результатів lsрідко є хорошою ідеєю , але отримання перших кількох полів є винятком, воно фактично працює на всіх "традиційних" об'єднаннях (це не працює на платформах, таких як деякі Windows-операції, які дозволяють пробіли в іменах користувачів).

ls -ld /path/to/directory | awk 'NR==1 {print $3}'

Інший варіант полягає у використанні statкоманди, але проблема з statоболонкою полягає в тому, що є кілька команд з різним синтаксисом, тому statв скрипті оболонки є нерепортажним (навіть через установки Linux).

Зауважте, тестування того, чи є власник даного користувача, є іншою пропозицією.

if [ -n "$(find . -user "$username" -print -prune -o -prune)" ]; then
  echo "The current directory is owned by $username."
fi
if [ -n "$(find . -user "$(id -u)" -print -prune -o -prune)" ]; then
  echo "The current directory is owned by the current user."
fi

На ls | awkжаль, є деякі застереження з підходом, як я вже зазначив . Я ще не знайшов рішення для проблеми "цільовий файл / реж - це симпосилання з іншим ім'ям", про яку я згадував у своєму недавньому коментарі.
beporter

Замість цього find . -user "$username" -print -prune -o -pruneви могли просто зробитиfind . -maxdepth 0 -user "$username"
Ніклас Холм

@Gilles Чи є причина, яку ви використовуєте awk 'NR==1 {print $3}'замість просто awk '{print $3}'? Я не впевнений, навіщо NR==1це потрібно тут.
Гарольд Фішер

1
@HaroldFischer Лише у крайньому випадку, де шлях містить новий рядок. Це рідко потрібно, але ніколи не шкідливо.
Жиль

@Gilles Дуже добре знати !! Цікаво, чи знаєте ви про реалізацію, lsколи нова лінія на шляху викликає розбиття лінії на два (що, я вважаю, це крайній випадок, який ви намагаєтесь охопити)? У GNU ls(нова версія), BusyBox lsта FreeBSD lsповертається новий рядок як $'\n', ?і ?відповідно.
Гарольд Фішер

9

Можна також зробити це за допомогою пошуку GNU:

find $directoryname -maxdepth 0 -printf '%u\n'

Це не портативно за межами системи GNU, але я був би здивований, коли знайшов дистрибутив Linux там, де він не працює.


1
Це працює для кожної невбудованої системи Linux та кількох інших (наприклад, Cygwin). Вбудовані системи, ймовірно, мають Busybox , якого findне має -printf.
Жиль,

Як я вже сказав, система GNU.
mattdm

Системи без ядер GNU (такі як FreeBSD) не мають -printf:-(.
pevik

@pevik Так, як я вже сказав. Але ви можете встановити GNU find, якщо вам це потрібно. :)
mattdm

@mattdm: не завжди :-(. Найголовніше, коли ви пишете сценарії, які повинні бути портативними.
pevik

2

У чистому bash ви можете перетворити вихідний lsмасив у масив та індексувати його.

# (lrwxr-xr-x, 1, myuser, staff, 36, Oct, 21, 16:36, /path/to/file)    
file_meta=($(ls -ld /path/to/file))
file_owner="${file_meta[2]}" # myuser

Це не так елегантно , як використання stat, findабо awk, але може працювати в крайньому випадку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.