Bash :Совместное использование if и find для проверки папок на наличие файлов

Такие факторы, как PLTкосвенность или syscall()'sвариативность -ness (регистры должны быть сохранены в памяти )должны играть небольшую роль, учитывая, что getdentsявляется одним из самых дорогих вызовов в Linux.

Полное чтение пустого каталога на моей машине занимает около 5 мкс, каталога из 100 -элементов — 37 мкс, каталога из 1000 -элементов — 340 мкс, а каталога из 10 000 -элементов — 3,79 мс.

Что fdopendir+ readdirделает поверх getdents, так это добавляет выделение/освобождение буфера (0,1 мкс )и statпроверку того, что предоставленный fd относится к разновидности каталога (0,4 мкс ). readdirзатем делает один дешевый вызов для каждой записи каталога (перемещает позицию в буфере и, возможно, перезаполняет ).

Таким образом, есть что-то вроде одного -временного накладного расхода в 0,5 мкс, что составляет 10% времени сканирования каталога для пустых каталогов, но только 1% для каталогов из 100 -элементов и ничтожно мало для больших каталогов. Эти накладные расходы в 5 раз меньше (только стоимости выделения/освобождения ), если вам не нужен fdopen.(вам нужен fdopen только в том случае, если вы не можете diropenнапрямую и, следовательно, должны использовать отдельно полученный (например, openat'ted )файловый дескриптор ).

Таким образом, если вы используете собственный -выделенный по времени буфер вместе с getdents, вы можете сэкономить 2 -10% на стоимости сканирования пустых каталогов и ничтожно мало на больших те.

Что касается вызовов readdir, стоимость косвенного обращения PLT на современном оборудовании обычно составляет менее 1 нс, служебные затраты на вызов функции составляют около 1 -2 нс. Учитывая, что время сканирования каталога составляет порядка микросекунд, вам нужно будет сделать не менее 1000 readdirвызовов, чтобы эти коэффициенты были переведены в одну мкс, но тогда стоимость сканирования составляет 340 мкс, а накопленная 1 дополнительная мкс равна примерно 0,3% от этого --незначительного эффекта. Встраивание этихreaddir(таким образом устраняет накладные расходы на вызовы и накладные расходы PLT )только для расширения кода, но это не сильно улучшит производительность, поскольку getdentsявляется здесь очень узким местом.

(readdir_rдороже из-за дополнительной блокировки, но вам не нужно readdir_r, потому что обычные вызовы readdirобычно являются потокобезопасными -, если только у вас нет нескольких потоков, вызывающих их на ] тот же поток каталога . POSIX, возможно, еще не говорит об этом явно, но я считаю, что эта гарантия должна быть стандартизирована в ближайшее время, учитывая, что glibc зашел так далеко, что объявил readdir_rустаревшим.)

2
19.05.2021, 17:56
2 ответа

[... ]проверяет строковые или числовые выражения. Если вы хотите увидеть, соответствует ли команда find, вам нужно проверить, предоставила ли она какой-либо вывод (непустую строку -, протестированную с помощью-n).

if [[ -n "$(find -name 'out.txt')" ]]
then
    echo "out.txt found in $folder"
fi

Обратите внимание, что я использую современный синтаксис $(...)для захвата вывода команды вместо устаревших обратных кавычек `...`.

Другие комментарии,

  • Вы можете упростить njobs=wc ${joblist} | awk '{print $1}' ``с njobs=$(wc -l <"$joblist"), чтобы получить только количество строк.

  • Передать $iв awkкак переменную,folder=$(awk -v i="$i" 'NR==i {print}' "$joblist}")

  • Не cdво вложенную папку, а затем полагаться на использование cd, чтобы вернуться туда, где вы были. Либо используйте относительные пути для ссылки на подкаталог, либо используйте подоболочку, чтобы сохранить cdв ограниченном контексте. Здесь я использую первый подход

      echo "$folder"
      if [[ -n "$(find "$folder" -name 'out.txt')" ]]
      then
          echo "out.txt found in $folder"
      fi
    
  • Если $folderвсегда является относительным путем, то ссылайтесь на него везде, где он используется как путь, как "./$folder". Это защищает от того, чтобы он начинался с тире (-), что может сбить с толку команды, которые могут попытаться интерпретировать его как ряд опций.

  • В оболочке bashуже есть переменная для текущего рабочего каталога, поэтому вы можете упростить cwd=`pwd`доcwd="$PWD"

  • Используйтеhttps://shellcheck.net/для проверки кода. (Или установите его локально, если вы не хотите делиться личным кодом.)

2
28.07.2021, 11:30
#!/bin/bash
joblist='job_list.txt'
njobs=`wc ${joblist} | awk '{print $1}'`

cwd=`pwd`
while IFS= read -r line
do
        folder="$line"   #`awk '(NR=='${i}'){print}' ${joblist}`
        echo $folder
        cd ${folder}
        if [ -f out.txt ]
        then
                echo out.txt found in $folder
        fi
        cd ${cwd}
done < job_list.txt

Надеюсь, это помогло. Немного проще... line=current-line-from'job_list.txt'Он читает строку -за -строку, поэтому файл выглядит так:

folder1
folder2
folder234

мой вывод:

france1@macubuntu:/tmp/tmdf$ bash script.sh 
folder1
folder2
folder234
out.txt found in folder234
france1@macubuntu:/tmp/tmdf$ 

надеюсь помог...

1
28.07.2021, 11:30

Теги

Похожие вопросы