Есть ли какие-то преимущества в указании './' в цикле for с использованием glob?

Я видел этот вопрос по stackoverflow, но мне не понравился ни один из ответы, и это действительно вопрос, который в любом случае должен быть здесь, на U&L.

Обычно индексный дескриптор используется для каждого файла в файловой системе. Таким образом, исчерпание inodes обычно означает, что у вас много маленьких файлов. Таким образом, действительно возникает вопрос: «В каком каталоге находится большое количество файлов?»

В этом случае файловая система, о которой мы заботимся, - это корневая файловая система / , поэтому мы можем использовать следующую команду :

find / -xdev -printf '%h\n' | sort | uniq -c | sort -k 1 -n

Будет выведен список всех каталогов файловой системы с префиксом количества файлов (и подкаталогов) в этом каталоге. Таким образом, каталог с наибольшим количеством файлов будет внизу.

В моем случае получается следующее:

   1202 /usr/share/man/man1
   2714 /usr/share/man/man3
   2826 /var/lib/dpkg/info
 306588 /var/spool/postfix/maildrop

Итак, в основном / var / spool / postfix / maildrop потребляет все inodes.

Обратите внимание, у этого ответа есть три предостережения, о которых я могу подумать. Он ничего не обрабатывает должным образом с символами новой строки в пути. Я знаю, что в моей файловой системе нет файлов с символами новой строки, и, поскольку это используется только для человеческого потребления, потенциальную проблему не стоит решать (и всегда можно заменить \ n на \ 0 и используйте sort -z выше). Он также не работает, если файлы разбросаны по большому количеству каталогов. Однако это маловероятно, поэтому я считаю риск приемлемым. Он также будет подсчитывать жесткие ссылки на один и тот же файл (поэтому используется только один индексный дескриптор) несколько раз.Опять же, вероятность ложных срабатываний маловероятна


. Основная причина, по которой мне не понравился ни один из ответов на вопрос stackoverflow, заключается в том, что все они пересекают границы файловой системы. Поскольку моя проблема была в корневой файловой системе, это означает, что она будет проходить через каждую подключенную файловую систему. Использование -xdev в командах поиска даже не сработает должным образом.
Например, наибольшее количество голосов получил следующий ответ:

for i in `find . -type d `; do echo `ls -a $i | wc -l` $i; done | sort -n

Если мы изменим его на

for i in `find . -xdev -type d `; do echo `ls -a $i | wc -l` $i; done | sort -n

, даже если / mnt / foo является маунтом, это также каталог в корневой файловой системе, поэтому он появится в find. -mount -type d , а затем он будет передан в ls -a $ i , который погрузится в монтирование.

find в моем ответе вместо этого перечисляет каталог каждого файла на монтировании. Итак, в основном с файловой структурой, такой как:

/foo/bar
/foo/baz
/pop/tart

, мы получаем

/foo
/foo
/pop

Так что нам просто нужно подсчитать количество повторяющихся строк.

10
25.02.2019, 16:22
1 ответ

Поначалу это удивительное поведение подстановочного знака, так как описание подстановочного знака *гласит:

Matches any string, including the null string.

... пока вы не поймете, что точка немного особенная, когда это первый символ имени файла. Вступительный текст в 3.5.8 Filename Expansionговорит об этом:

When a pattern is used for filename expansion, the character ‘.’ at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set.

«Шаблон использования» подстановочных знаков с префиксом ./полезен для обработки имен с начальным дефисом в оболочке bash , как прокомментировал steeldriver. Это не влияет на подстановочный знак/расширение имени файла, но делает более безопасной/легкой обработку имен файлов, когда вы ссылаетесь на них, если они начинаются с символов, которые эти программы могут ошибочно интерпретировать как параметры. Например:

# I want a file named `-n`
$ touch -n
touch: invalid option -- 'n'
Try 'touch --help' for more information.
$ touch -- -n
### ok
$ touch./-n
### ok

... и теперь, когда у меня есть файл с именем -n, если мне случится перебрать его с подстановочным знаком:

for file in *n
do
  echo "$file"
done

... У меня нет вывода!

Но если я добавлю к подстановочному знаку префикс ./,

for file in./*n
do
  echo "$file"
done
./-n

... Я вижу имя файла.

Это простой пример для демонстрационных целей;см. также Почему printf лучше, чем echo? по этой и другим причинам. Другие утилиты будут сбиты с толку другими параметрами, поэтому лучше предоставлять имена файлов утилитам как можно более безопасно. Если вы не ставите префикс подстановочного знака для «экранирования» имен файлов, вам придется «защищать» свои утилиты другими способами; один общий один сигнализирует об окончании опций с помощью --, например:

for file in *n
do
  mv -- "$file" backup/"$file"
done

... который безопасно передаст имя файла -nв mv(, как показано вset -x):

mv -- -n backup/-n
15
27.01.2020, 20:01

Теги

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