Оу, бях останал с впечатлението, че просто търсим нещо, с което да се свърши някаква конкретна работа. Щом е с образователна цел, тогава всичко се променя - много ми харесва скриптът ти в такъв случай

Сега, първо някои препоръки в сегашния му вид:
1. Не пренебрегвай началния ред с указател за shell-а, който да се използва при изпълнението на скрипта. Ако оставиш скрипта без такъв ред, тогава скриптът ще се изпълни с shell-а, който потребителят, изпълнил скрипта, използва текущо в конзолата си, а той може не винаги да е shell-ът, чийто синтаксис си следвал при писането на скрипта. Ако си изписал скрипта си напълно със синтаксис, поддържан от всички shell-ове, тогава няма да имаш проблеми, но ако не си сигурен, че си го направил (аз лично никога не съм сигурен, макар че пиша отдавна), указването на този ред ще те спаси от грешки, заради неподдържан синтаксис в shell-а на потребителя. Bash е отличен shell за повечето нужди, вероятно си забелязал, че използвам основно него, но ти си прецени кой shell предпочиташ. Само си провери и напиши синтаксиса спрямо това, което избраният от теб shell поддържа;
2. Не си вмъкнал четене на аргумент с името на началната директория за търсене. Това те принуждава всеки път предварително в конзолата да отиваш до началната папка, в която искаш да търсиш, вместо просто да подадеш пътя (било пълен или относителен) до началната папка към скрипта и всичко да е в една команда. При сегашната структура на скрипта, просто добавяйки в скрипта предварително cd към папката в аргумента няма да те задължи да подаваш аргумент с папката. Ако не подадеш, ще се търси в текущата папка, в която си;
3. Ползвай еднакви отстояния в подредбата на кода в различните редове с еднаква вложеност. В момента кодът ти е разместен, което го прави по-трудно четим, дори и от теб, което може да доведе до загуба на последователността от пишещия и грешни редактирания. Хубаво е да има и по един празен ред между по-основните парчета код за още по-добра видимост, но да речем, че е с по-малка важност от равните отстояния;
4. Винаги дефинирай предварително променливите, които използваш в условия на проверки и цикли, освен ако целта наистина не е недефинирана променлива. Това важи в особена степен за променливите, които ползваш за съхранение на числа, тъй като много числови функции зависят от това стойността да е наистина число, а никога нямаш нужда да сравняваш числово някакво число с нищо. В момента скриптът се оплаква за нечисловата стойност на $var в while, когато for се завърта за първи път. Предварително задаване на $var да е равно на нула те предпазва от началната му нечислова стойност;
5. Отново ти обръщам внимание за нуждата от кавички, когато работиш с имена на файлове и директории (и, въобще, с текстове, които може да съдържат интервали), за да не получиш неочаквани резултати. Освен това принципно е хубаво да използваш кавички за променливите, намиращи се в квадратни скоби, като тези на if и while (не само защото скриптът в момента изкарва грешка и за това);
6. Каква е работата на този eval там? За това сумиране не е нужен eval. Функцията eval служи да превърнеш текст в код. В този ред нямаш такова нещо. Освен това сумиращата функция в bash приема стринговете автоматично за променливи, така че не е нужно да слагаш $ пред var там, но това си е по твоя преценка. За прегледност на кода е хубаво и да си избереш един от двата синтаксиса на сумиращата функция (с двойни кръгли скоби, като при var, или с единични квадратни, като при j;
7. Не е нужно указването на ./ при cd за влизане в поддиректория на текущата. Не е и нужно отместването в дървото да е чак толкова голямо, колкото е табулацията по подразбиране, в конзолата обикновено се използват букви с равна широчина, така че 4 интервала биха били достатъчни като отместване и не биха предизвикали различни отмествания по брой букви в различните редове.
Ето ти го скрипта с приложените предложения, ако нещо не съм го описал ясно, пък ти си решавай кое ще ползваш и кое - не
GeSHi (Bash):
#!/bin/bash
filefind ()
{
for i in *; do
if [ -d "$i" ]; then
j=1
while [ "$j" -le "$var" ]; do
printf " "
j=$(( j + 1 ))
done
echo "$i"
cd "$i"
var=$(( var + 1 ))
filefind
fi
done
var=$(( var - 1 ))
cd ..
}
cd "$1"
var=0
filefind
Сега, за добавянето на изпълнимите файлове към изведения списък. Тук отново имаме двата варианта, спрямо това кои изпълними файлове искаш да се извеждат - тези, които потребителят, изпълнил скрипта, може да изпълнява, или всички файлове, съдържащи бит за изпълнение в някоя от групите права.
Пример за варианта, при който се извеждат само файловете, които потребителят, изпълнил скрипта, може да изпълнява:
GeSHi (Bash):
#!/bin/bash
filefind ()
{
for i in *; do
if [[ (-d "$i" && -x "$i" && ! -h "$i") || (-f "$i" && -x "$i") ]]; then
j=1
while [ "$j" -le "$var" ]; do
printf " "
j=$(( j + 1 ))
done
if [ -d "$i" ]; then
echo "$i/"
cd "$i"
var=$(( var + 1 ))
filefind
else
echo "$i"
fi
fi
done
var=$(( var - 1 ))
cd ..
}
cd "$1"
var=0
filefind
Обърни внимание, че съм добавил различно echo, спрямо това дали е файл или директория, за да се различават по някакъв начин в списъка после. Може да си добавиш и други различаващи знаци, ако искаш. Може и да премахнеш разликата, но не те съветвам. А проверките в if-а на ред 6 станаха много, заради защитите от проби за листване на рекурсивни symlink-ове (онези, за които в предния пост ти писах, че ще ти създадат проблеми) и листване на папки, за които потребителят няма права да ги листва (което също би довело до безкраен цикъл).
Пример за варианта, при който се извеждат всички файлове, съдържащи бит за изпълнение в някоя от групите права:
GeSHi (Bash):
#!/bin/bash
filefind ()
{
for i in *; do
if [[ (-d "$i" && -x "$i" && ! -h "$i") || (-f "$i" && "$(stat -c %A "$i" 2>/dev/null | grep '[x|s|t]')") ]]; then
j=1;
while [ "$j" -le "$var" ]; do
printf " "
j=$(( j + 1 ))
done
if [ -d "$i" ]; then
echo "$i/"
cd "$i"
var=$(( var + 1 ))
filefind
else
echo "$i"
fi
fi
done
var=$(( var - 1 ))
cd ..
}
cd "$1"
var=0
filefind
Тук използваме командата stat, за да изведем пълния списък от права на съответния файл или папка. Да не те притеснява, малък инструмент е и го има във всяка дистрибуция. В grep съм описал търсене не само на "x" правило, но и на "s" и "t" правило, за да покрием случаите, когато, освен бит за изпълнение, към съответната група права поради някаква причина е зададено и някое от специалните права SUID (ще имаме "s" вместо "x" в правата за потребителя-собственик), SGID (ще имаме "s" вместо "x" в правата за групата-собственик) и sticky bit (ще имаме "t" вместо "x" в правата за други). Ако някое от тези специални права е зададено, но в съответната група права нямаме зададен бит за изпълнение, тогава буквите им биха били големи ("S" и "T"), така че нямаме проблем с това, както сме описали малки букви в grep и не сме задали да не прави разлика между малки и големи букви.
Разбира се, в скрипта може да се обединят и двата варианта на търсене и с аргумент към скрипта потребителят да си избира дали да търси само файловете, които може да изпълнява, или да търси всички файлове, които имат бит за изпълнение в някоя от групите права. Оставям на теб да го направиш, ако ти се занимава, че и без това постът ми стана много дълъг