Почему ls -i медленнее ls?

Аргументы утилиты передаются как список строк, а не как одна строка. Поэтому утилита не имеет понятия разделителя между аргументами. Аргументы - это просто отдельные элементы списка, между ними ничего нет.

Сущность, которая разделяет строку на список аргументов, - это оболочка. Оболочка выполняет командную строку типа /bin/kill $(echo "75341 75342"), выполняя серию расширений. В частности:

  1. Команда разбивается на токены. Я не буду подробно останавливаться на этих правилах; токен - это либо знак препинания, либо последовательность символов, не содержащая пробельных символов верхнего уровня. Здесь токенами являются строка /bin/kill и подстановка команды $(echo "75341 75342"), которая сама строится из оператора $(...) и токенов echo и 75341 75342.
  2. Команда в операторе подстановки команд выполняется. Это простая команда с именем echo и единственным аргументом 75341 75342. (Кавычки являются частью синтаксиса оболочки, они разграничивают строку, которая становится аргументом команды)
  3. Вывод команды - 75341 75342␤, где - символ новой строки. Оболочка возьмет этот вывод и удалит последние новые строки, получив строку 75341 75342.
  4. Поскольку оператор подстановки команд используется в контексте списка (вне двойных кавычек), он подвергается разбиению на слова и расширению имени файла. Разбиение слов состоит в том, что строка берется и разбивается на список строк на основе значения переменной IFS. По умолчанию IFS содержит символы пробела, табуляции и новой строки, поэтому строка разбивается на любую последовательность этих символов: она становится списком из двух строк 75341 и 75342. Расширение имени файла здесь ничего не меняет.
  5. Теперь у нас есть список из трех строк: /bin/kill, 75341 и 75342. Это выполняется как команда /bin/kill с двумя аргументами 75341 и 75342.

С командой /bin/kill $(echo -e "75577\n75578"), расширения практически те же. Шаг 3 дает результат 75341␤75342␤. На шаге 4 разбиение слов на части дает тот же список 75341, 75342, что и раньше, поскольку новая строка и пробел являются одинаково допустимыми разделителями слов. Таким образом, шаг 5 выполняет точно такую же команду.

Как видите, шаг, определяющий, что разделяет аргументы, - это шаг разделения слов, выполняемый оболочкой. Вы можете поэкспериментировать с этим шагом, изменив значение IFS. Например, это снова приводит к той же команде:

IFS=+
/bin/kill $(echo "75341+75342")

0
21.07.2018, 07:35
1 ответ

strace показывает мне, что ls -iвызывает lstat()для каждого имени файла

Это объясняет дополнительную работу.

Учитывая, что readdir ()уже вернул номер инода, это кажется менее -оптимальным

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

8
28.01.2020, 02:13

Теги

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