Не могу отнести данный код к супер-полезным или сложным, однако, это довольно занятное упражнение: если возникает какая-то задача - решать ещё однострочником на Bash. Получается такая своеобразная гимнастика для ума. Ну и позволяет не забывать основные команды Bash.
Код ниже пройдётся по всем вложенным в текущую директорию файлам, посчитает количество строк, сложит вместе и выведет на консоль:
find -type f -name \*.c -exec wc -l {} \; \
| cut -d' ' -f1 \
| while read line; do \
res=$(($res + $line)); \
echo $res; \
done \
| tail -1
Для удобства я его отформатировал, а чтобы Bash не замечал переводы строк -
заэкранировал их символом \
.
Начнём с первой строки:
find -type f -name \*.c -exec wc -l {} \;
С помощью утилиты find можно рекурсивно
пробежаться по директории в поисках нужных файлов. Так, к примеру, сейчас
мы ищем по типу "f" - файлы (-type f
), имя которых заканчивается на "*.c"
(-name \*.c
). При чём символ "*" нам нужно экранировать, ведь иначе
Bash попытается подставить аргументом файлы, подходящие под шаблон. В нашем случае - *.с
.
С помощью же ключа -exec
мы также просим find
для каждого файла выполнить
команду. В нашем случае используем утилиту wc - wc -l
- посчитать строки:
$ find -type f -name \*.c -exec wc -l {} \;
38 ./t/test_x.c
45 ./t/test_y.c
49 ./t/test_z.c
224 ./main.c
267 ./inc/x.c
38 ./inc/y.c
77 ./inc/z.c
...
Теперь мы имеем 2 колонки, разделённые пробелом: количество строк, имя файла.
Вторая колонка нам неинтересна, поэтому вырежем её утилитой cut:
cut -d' ' -f1
Устанавливаем разделителем пробел (-d' '
), оставляем 1-ую колонку (-f1
).
Если возник вопрос о том, зачем нужна вертикальная черта между командами, подробнее - в заметке о потоках ввода-вывода. Если коротко - с помощью неё как по трубе передаём данные от одной команды к другой.
На данный момент наши данные приняли вид:
$ find -type f -name \*.c -exec wc -l {} \; | cut -d' ' -f1
38
45
49
224
267
38
77
...
Теперь нам нужно просуммировать строки. И здесь нам потребуется цикл while. Считываем строчку за строчкой, а в теле цикла суммируем их и выводим результат:
res=$(($res + $line)); \
echo $res; \
Теперь в последней строке вывода будет искомое число. Получаем его утилитой tail. Ключ указывает на то, сколько строк с конца мы хотим получить: tail -1
-
получить последнюю строку.
Думаю, теперь понятно, как работает однострочник, представленный в начале заметки.