Перерахуйте всі каталоги, у яких НЕ є файл із заданим ім’ям всередині


12

Як би я перейшов до переліку всіх каталогів, у яких немає файлу із заданим ім'ям файлу всередині? наприклад, дане дерево

/
  /a
     README
     file001
     file002
  /b
     README
     file001
  /c
     file003

Я хочу перерахувати каталоги, у яких немає імені файлу README, в цьому випадку це буде каталог /c. Як би я це зробив? Я не можу думати про яку - або синтаксису з використанням , наприклад find.


Сором о сором, що ти навіть не шукав: askubuntu.com/questions/196960/…
slm

Я, мабуть, не придумав правильних ключових слів під час пошуку.
Ренан

2
Я просто перебираю твої відбивні. Я багато разів бував там, де не міг придумати правильного слова, щоб шукати щось 8-).
slm

Відповіді:


5

Якщо припустити таку findреалізацію, як GNU, findяка приймає {}вбудований аргумент -exec:

$ find . -type d \! -exec test -e '{}/README' \; -print

Приклад

Тут каталоги 1/1 до 5/5 мають README, інші папки порожні.

$ tree 
.
|-- 1
|   `-- 1
|       `-- README
|-- 10
|   `-- 10
|-- 2
|   `-- 2
|       `-- README
|-- 3
|   `-- 3
|       `-- README
|-- 4
|   `-- 4
|       `-- README
|-- 5
|   `-- 5
|       `-- README
|-- 6
|   `-- 6
|-- 7
|   `-- 7
|-- 8
|   `-- 8
`-- 9
    `-- 9

Тепер, коли ми запускаємо цю версію нашої findкоманди:

$ find . -type d \! -exec test -e '{}/README' \; -print
.
./10
./10/10
./7
./7/7
./9
./9/9
./6
./6/6
./5
./8
./8/8
./4
./1
./3
./2

Список літератури


Як змінити команду для пошуку підкаталогів, які не мають певного розширення файлу (скажімо * .txt). Зміна README за допомогою * .txt, здається, не працює
WanderingMind

@WanderingMind - якщо у вас є нове запитання, будь ласка, задайте його як новий на сайті ;-)
slm

3

Ви можете скористатися -execопцією, findщоб перевірити файл, а потім надрукувати всі результати, на які перевірка не вдалася.

find /path/to/base -mindepth 1 -maxdepth 1 -type d -exec test -e {}/README \; -o -print

3

Не потрібно find. Просто використовуйте оболонку:

for d in */; do [ -f "$d"README ] || printf '%s\n' "$d"; done
c/

Якщо вам потрібно, щоб він був рекурсивним, ви можете використовувати (для bash, zshможна зробити це за замовчуванням, використовувати set -o globstarв ksh93):

shopt -s globstar
for d in **/; do [ -f "$d"README ] || printf '%s\n' "$d"; done

(зауважте, що точки-файли за замовчуванням виключаються).


2

За допомогою zshта глобальних класифікаторів ( eрядок ):

print -rl -- *(/e_'[[ ! -f $REPLY/README ]]'_)

або

print -rl -- *(/^e_'[[ -f $REPLY/README ]]'_)

додати, Dщоб включити приховані каталоги:

print -rl -- *(D/e_'[[ ! -f $REPLY/README ]]'_)

/вибирає лише каталоги та e_'[[ ! -f $REPLY/README ]]'_надалі вибирає лише імена каталогів, для яких повертається код оболонки між цитатами true, тобто для кожного імені каталогу ( $REPLY), на яке *(/)розширюється глобус , він запускає [[ ! -f $REPLY/README ]]та зберігає ім'я каталогу, якщо результат є true.
У другій формі ^e_'.....'_використовується той самий глобальний класифікатор, який заперечується (але цього разу умовний вираз не заперечується:) [[ -f $REPLY/README ]].


Сказане повертає лише імена каталогів у поточному каталозі.
Якщо ви хочете шукати рекурсивно (знову ж таки, для включення прихованих каталогів додайте Dкваліфікатор):

print -rl ./**/*(/e_'[[ ! -f $REPLY/README ]]'_)

2

Портативно, ви можете:

find . -type d -exec sh -c '
  for dir do
    [ -f "$dir/README" ] || printf "%s\n" "$dir"
  done' sh '{}' +

[ -f file ]перевіряє, чи існує файл і чи підтверджено це звичайний файл (після роздільної здатності символьної посилання).

Якщо ви хочете перевірити, що він існує лише (як запис у цьому каталозі), незалежно від його типу, вам знадобиться: [ -e file ] || [ -L file ]хоч зауважте, що для виконання цих тестів вам потрібен дозвіл пошуку в каталозі. Ви можете додати кілька [ -x "$dir" ]тестів для обліку таких випадків, як:

find . -type d -exec sh -c '
  for dir do
    if [ -x "$dir" ]; then
      [ -f "$dir/README" ] || printf "%s\n" "$dir"
    else
      printf >&2 "Cannot tell for \"%s\"\n" "$dir"
    fi
  done' sh '{}' +

Або щоб уникнути умови гонки, використовуючи zsh:

find . -type d -exec zsh -c '
  zmodload zsh/system
  for dir do
    ERRNO=0
    if [ ! -f "$dir/README" ]; then
      if [ "$errnos[ERRNO]" = ENOENT ]; then
        printf "%s\n" "$dir"
      else
        syserror -p "ERROR: $dir/README: "
      fi
    fi
  done' zsh '{}' +

Дивіться також Як дізнатися, чи не існує звичайного файлу в Bash? на ТАК.

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