Загрузка данных


Давайте разберем эту конвейерную команду по шагам. Она обрабатывает файл suid_sgid.txt, содержащий полные пути к файлам (по одному на строку).

Исходные данные
Файл suid_sgid.txt содержит строки вида:

text
/usr/bin/passwd
/usr/bin/sudo
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/bin/su
/usr/bin/passwd
/bin/mount
Разбор команды по частям
1. cat suid_sgid.txt
Действие: Выводит содержимое файла в stdout

Результат: Поток строк с полными путями файлов

2. | awk -F '/' '{$NF=""; print $0}'
-F '/' : Устанавливает разделитель полей (Field Separator) — символ /

$NF : NF = Number of Fields, $NF — последнее поле (имя файла)

{$NF = ""; print $0} : Обнуляет последнее поле (стирает имя файла), затем печатает всю строку $0

Результат: Из каждого пути удаляется имя файла, остаются каталоги с завершающим слэшем

Пример преобразования:

text
Вход:    /usr/bin/passwd
Поля:    "" | "usr" | "bin" | "passwd"
            $1    $2      $3      $4($NF)
После:   /usr/bin/
(потому что $4 стал пустым, а разделители на месте)
Проблема: AWK выводит поля, разделенные FS (/), но пустое последнее поле создает два смежных разделителя:

text
/usr/bin/   ← Здесь два слэша? Нет, AWK выводит /usr/bin/
Фактически: FS между $1($2) и $2($3): /usr/bin
Пустой $NF не добавляет слэш автоматически
3. | tr ' ' '/'
Действие: Заменяет все пробелы на слэши

Важно: AWK выводит поля, разделенные пробелом (по умолчанию OFS=" ")

AWK что вывел на самом деле:

text
/usr/bin/            ← но здесь нет пробелов... Стоп!
Проблема в анализе: В AWK print $0 печатает строку с разделителями полей (ORS — Output Field Separator, по умолчанию пробел), но здесь $0 — пересобранная строка с удаленным полем. На самом деле AWK выводит пробелы как разделители между частями пути.

Пример с отладкой:

text
echo "/usr/bin/passwd" | awk -F '/' '{$NF=""; print $0}'
Вывод: /usr/bin/   (с пробелом? нет — но это зависит от реализации)
Честно говоря, в классическом AWK print $0 выводит поля, соединенные OFS (пробел). Без имени файла будет:

text
/ usr bin   → между ними пробелы!
4. | sort
Действие: Сортирует все строки в алфавитном порядке

Результат: Одинаковые каталоги группируются вместе

5. | uniq -c
Действие: Подсчитывает количество одинаковых строк

-c: Count — показывает число повторений перед каждой уникальной строкой

ИТОГОВЫЙ СМЫСЛ КОМАНДЫ
Команда считает, сколько раз каждый каталог встречается в списке файлов (без учета самих файлов).

Более чистый эквивалент:
bash
cat suid_sgid.txt | awk -F '/' '{print $(NF-1)}' | sort | uniq -c
# или еще проще:
awk -F '/' '{print $(NF-1)}' suid_sgid.txt | sort | uniq -c
Пример работы:
Вход (suid_sgid.txt):

text
/usr/bin/passwd
/usr/bin/sudo
/usr/lib/security/pam_rootok.so
/bin/su
/usr/bin/crontab
/bin/mount
Вывод команды:

text
      2 bin
      1 lib
      2 usr
Потому что:

bin встречается 2 раза (у /bin/su и /bin/mount — но тут ошибка, /bin/mount дает каталог bin)

usr встречается 3 раза? Нет, passwd, sudo, crontab — все в /usr/bin

Лучше переписать правильно:

bash
awk -F '/' '{
    # Удалить последнее поле (имя файла)
    path = ""
    for(i=1; i<NF; i++) {
        path = path "/" $i
    }
    print path
}' suid_sgid.txt | sort | uniq -c
Типичный вывод:
text
      3 /usr/bin
      2 /bin
      1 /usr/lib/security
      1 /usr/lib/dbus-1.0
Проблемы исходной команды:
tr ' ' '/' странная — если в AWK уже есть слэши, замена пробелов делает кашу

На выходе будут каталоги с лишними пробелами или двойными слэшами

Лучше использовать чистое решение без tr

Вывод: Команда пытается сгруппировать файлы по каталогам и подсчитать количество файлов SUID/SGID в каждом каталоге, но из-за tr делает это некорректно.