Автор Тема: shell script  (Прочетена 10520 пъти)

villimon

  • Напреднали
  • *****
  • Публикации: 65
    • Профил
Re: shell script
« Отговор #15 -: Oct 22, 2013, 08:15 »
Намерих, че >& пренасочва стандартния изход и стандартния изход за грешки. Така беше написано. Искам просто нищо от тази команда да не стига до конзолата.
Искам да се изведат само файловете но да са в дървовидна форма.
n00b казва :
Може да използваш awk и да броиш / като ги заместваш със табове и да се получи желания резултат.
Това не мога да си представя как ще стане.
Иначе tree върши добра работа най-вероятно ще е трудно с други инструменти, защото предполагам този е създаден за такива чели.
Но ми е интересно по какви други начини може да стане, мислех си за обработка на резултата от команда като string но не знам дали изобщо е възможно.
Иначе може ли да питам  Slackware какъв пакетни мениджър използва.
Активен

neter

  • Global Moderator
  • Напреднали
  • *****
  • Публикации: 3408
  • Distribution: Debian, SailfishOS, CentOS
  • Window Manager: LXDE, Lipstick
    • Профил
    • WWW
Re: shell script
« Отговор #16 -: Oct 22, 2013, 11:06 »
Искам да се изведат само файловете но да са в дървовидна форма.
Ако се извеждат само файловете, по какво ще видиш дървото? Нека изпълним
Код
GeSHi (Bash):
  1. tree -F | grep '[*|/]'
и имаме такъв изход от директории и изпълними файлове
Цитат
├── proba*
├── test/
│   ├── proba1*
│   └── test2/
│       └── proba2*
├── test1/
В този изход файлът proba се намира в основната директория, файлът proba1 се намира в подпапка test, файлът proba2 се намира в подпапка test2 на подпапка test, а подпапка test1 не съдържа изпълними файлове. Ако на grep кажем да остави само файловете (т.е., му укажем само звездичка в квадратните скоби), изходът ще изглежда така
Цитат
├── proba*
│   ├── proba1*
│       └── proba2*
при което се вижда, че proba1 е в подпапка, но не се знае коя. За да знаем коя е папката, може да добавим флаг "-f" към tree, за да се изписва пътят до файла
Код
GeSHi (Bash):
  1. tree -Ff | grep '[*]'
при което изходът ще изглежда така
Цитат
├── ./proba*
│   ├── ./test/proba1*
│       └── ./test/test2/proba2*
Вижда се кой файл е в основната директория, кой файл е в подпапка и имената на директориите се изписват при самите файлове.

Какъв изход предпочиташ - имената на папките да са на отделни редове или да са част от името на файла? Имаш ли нужда от такова визуално представяне на дървото (с линии) или ти е достатъчно просто съответно отместване?
Активен

"Да си добре приспособен към болно общество не е признак за добро здраве" - Джиду Кришнамурти

villimon

  • Напреднали
  • *****
  • Публикации: 65
    • Профил
Re: shell script
« Отговор #17 -: Oct 22, 2013, 14:20 »
Лично на мен този вариант
Цитат
├── proba*
├── test/
│   ├── proba1*
│   └── test2/
│       └── proba2*
├── test1/
ми допада най-много но искам да разбера как може да се изведе без линиите със съответното отместване. Ако не те затруднява.
Активен

neter

  • Global Moderator
  • Напреднали
  • *****
  • Публикации: 3408
  • Distribution: Debian, SailfishOS, CentOS
  • Window Manager: LXDE, Lipstick
    • Профил
    • WWW
Re: shell script
« Отговор #18 -: Oct 22, 2013, 16:21 »
искам да разбера как може да се изведе без линиите със съответното отместване
За да се махнат линиите в изхода на tree и да се запазят отместванията, трябва да се използва някой допълнителен инструмент, който да замени линиите с нещо друго. Например, с инструмента sed и замяна на линиите с интервали
Код
GeSHi (Bash):
  1. tree -F | grep '[*|/]' | sed 's/[├|─|└|│]/ /g'
Ако имаш проблеми с копирането от тук на тези четири знака, оформящи линиите в tree (├, ─, └ и │), въпреки че са UTF-8 и би трябвало да нямаш проблеми, може да си ги копираш от конзолата при теб, когато извикаш tree с налични линии.

П.П.: По-нагоре питаше кой е пакетният мениджър в Slackware. Това е pkgtool.
« Последна редакция: Oct 22, 2013, 16:27 от neter »
Активен

"Да си добре приспособен към болно общество не е признак за добро здраве" - Джиду Кришнамурти

villimon

  • Напреднали
  • *****
  • Публикации: 65
    • Профил
Re: shell script
« Отговор #19 -: Oct 22, 2013, 18:57 »
Сега ме за гложди въпроса тези символи как си ги написал и примерно не може ли да се заместят с ASCII кода разбирам че sed приема регулярен израз което е string. Дали има друга команда ?
Активен

neter

  • Global Moderator
  • Напреднали
  • *****
  • Публикации: 3408
  • Distribution: Debian, SailfishOS, CentOS
  • Window Manager: LXDE, Lipstick
    • Профил
    • WWW
Re: shell script
« Отговор #20 -: Oct 23, 2013, 00:01 »
Щом те притеснява директното изписване на тези символи може да ги заместиш с hex стойностите им. Малко по-дълго става, но...
Код
GeSHi (Bash):
  1. a=$(echo '0000000: e294 9c0a' | xxd -r);
  2. b=$(echo '0000000: e294 800a' | xxd -r);
  3. c=$(echo '0000000: e294 940a' | xxd -r);
  4. d=$(echo '0000000: e294 820a' | xxd -r);
  5. tree -F | grep '[*|/]' | sed "s/[$a|$b|$c|$d]/ /g"
Обърни внимание, че съм сменил вида на кавичките в частта със sed (станали са двойни), за да се четат вътре променливите като променливи, а не като текст. Може и с единични кавички, но ще трябва да ги прекъсваме на местата, където са променливите. Командата xxd би трябвало да си е налична в системата и без да качваш допълнителен пакет, но провери все пак.
Нещо не можах да го докарам правилното конвертиране на ASCII стойностите им обратно в тези символи. Ако някой има идея за нещо по-кратко нека сподели.
« Последна редакция: Oct 23, 2013, 00:21 от neter »
Активен

"Да си добре приспособен към болно общество не е признак за добро здраве" - Джиду Кришнамурти

n00b

  • Напреднали
  • *****
  • Публикации: 1248
  • Distribution: OSX
  • Window Manager: 10.6, 10.8, 10.9
  • Live to hack, hack to live.
    • Профил
Re: shell script
« Отговор #21 -: Oct 23, 2013, 01:37 »
пффф.. обърках AWK със SED, но гледам че със neter дерзаете
Активен

mobilio - професионални мобилни приложения

villimon

  • Напреднали
  • *****
  • Публикации: 65
    • Профил
Re: shell script
« Отговор #22 -: Oct 31, 2013, 17:05 »
Здравейте,
с риск да ви досадя до край ми щукна още един въпрос на който се надявам да можете да ми отговорите.
Има ли начин рекурсивно да обходя дърво на директориите от което да изведа изпълнимите файлове със съответното изместване отговарящо на вложеността.
Активен

neter

  • Global Moderator
  • Напреднали
  • *****
  • Публикации: 3408
  • Distribution: Debian, SailfishOS, CentOS
  • Window Manager: LXDE, Lipstick
    • Профил
    • WWW
Re: shell script
« Отговор #23 -: Oct 31, 2013, 18:04 »
Има ли начин рекурсивно да обходя дърво на директориите от което да изведа изпълнимите файлове със съответното изместване отговарящо на вложеността.
С какво това се различава от задачата досега?
Активен

"Да си добре приспособен към болно общество не е признак за добро здраве" - Джиду Кришнамурти

villimon

  • Напреднали
  • *****
  • Публикации: 65
    • Профил
Re: shell script
« Отговор #24 -: Oct 31, 2013, 18:53 »
идеята ми е вместо с tree да се направи с функция която практически ще прави същото като tree знам, че звучи тъпо ама в това му е интересното да се пресъздаде работата на tree
Активен

neter

  • Global Moderator
  • Напреднали
  • *****
  • Публикации: 3408
  • Distribution: Debian, SailfishOS, CentOS
  • Window Manager: LXDE, Lipstick
    • Профил
    • WWW
Re: shell script
« Отговор #25 -: Oct 31, 2013, 22:38 »
А, да! Аз нали ти обещах, че ще ти драсна и вариант без tree, ама ей го, трябвало още веднъж да си поискаш, за да се наканя :)
Малко набързо нахвърляно е и може би може да се оптимизира нещо тук-там, но ето с find
Код
GeSHi (Bash):
  1. #!/bin/bash
  2.  
  3. listArr=( $(find "$1" -perm /a+x -type f | sed 's/\.\///g') )
  4.  
  5. for file in "${listArr[@]}"; do
  6.    pathArr=( $(echo "$file" | sed 's/\//\/ /g') )
  7.    i=0
  8.    for row in "${pathArr[@]}"; do
  9.        printf %$(eval echo $i)s | sed 's/ /    /g'
  10.        echo "$row"
  11.        i=$((i + 1))
  12.    done
  13. done
Това го слагаш в скрипт и викаш скрипта с подаване на папка (променливата $1 служи да прочете подадения първи аргумент към скрипта)
Цитат
./име–на–скрипта.sh "/път/за/търсене"
Може да подаваш както пълен, така и относителен път до папката, в която ще се търси. Даже го изпробвай с двата вида пътища, за да видиш разликата. Забравих да го спомена в предните постове, но това с $1 и подаване на пътя като аргумент към скрипта важи и за примерите с tree (само си добави $1 след -F в реда с tree). Това е стандартният начин за директно подаване на аргументи към скриптове. $1 е първият аргумент, $2 е вторият аргумент и т.н., разделени с интервал в реда, в който извикваш скрипта. Заради отделянето с интервали е хубаво да имаш навика да ограждаш текста на аргументите с кавички, за да не се раздели текстът в отделни аргументи от случайни интервали (каквито може да има в имена на файлове и директории например).

П.П.: Забравих да ти кажа за "-perm /a+x", който можеш да видиш в реда с find. Целта на този аргумент към find е да изведе всичко, което има бит за изпълнение (+x), в която и да е (/a) от групите права (за потребителя-собственик, за групата-собственик или за други потребители), с което се постига като в tree да се извеждат всички изпълними файлове, независимо дали потребителят, изпълняващ скрипта, има право да ги изпълнява или не. Ако искаш да се търсят само изпълними файлове, които потребителят, изпълнил скрипта, има право да изпълнява, тогава замени този аргумент в кавичките с "-executable", т.е., редът с find ще стане
Код
GeSHi (Bash):
  1. listArr=( $(find $1 -executable -type f | sed 's/\.\///g') )
Ако решиш да е с -perm, обърни внимание, че наклонената черта в "/a" е нововъведение във find, което замени плюса (по старому щеше да бъде "+a"), за да удовлетвори едни POSIX спецификации. Едва ли ще ти се наложи, но ако някъде попаднеш на стар find, който не знае за наклонената черта, да знаеш, че е достатъчно да замениш наклонената черта с плюс. Но това, само ако се наложи. Засега в скрипта си го остави по препоръчителния нов синтаксис с наклонената черта.
« Последна редакция: Oct 31, 2013, 23:23 от neter »
Активен

"Да си добре приспособен към болно общество не е признак за добро здраве" - Джиду Кришнамурти

villimon

  • Напреднали
  • *****
  • Публикации: 65
    • Профил
Re: shell script
« Отговор #26 -: Nov 01, 2013, 09:20 »
Искам нещо такова да направя
filefind ()
{
    for i in *
   do
       if [ -d $i ]
      then j=1;
          while [ $j -le $var ]
         do
             printf "\t"
             j=$[j+1]
         done
      echo $i
      cd ./$i
      eval var=$(( $var + 1 ))
      filefind
       fi
   done
var=$(( $var - 1 ))
cd ..
}

filefind

тази функция рекурсивно обхожда директориите(-d) в дървото и ги извежда. Аз искам да изведе изпълнимите файлове с изместване съответстващо на вложеността. С eval var броя колко навътре се намирам за да знам колко таба да изведа. В тази насока ако може да помогнете.
« Последна редакция: Nov 01, 2013, 10:10 от villimon »
Активен

neter

  • Global Moderator
  • Напреднали
  • *****
  • Публикации: 3408
  • Distribution: Debian, SailfishOS, CentOS
  • Window Manager: LXDE, Lipstick
    • Профил
    • WWW
Re: shell script
« Отговор #27 -: Nov 01, 2013, 17:17 »
Извинявай за по-твърдото определение, но това са глупости. Съгласен съм, че твоят скрипт ще ползва по-малко RAM (по-горе в примера с find запазвам целия рекурсивен списък в listArr наведнъж), но колко голям списък ще обхождаш, че това да заима значение и да ти компенсира по-бавните последователни операции? Да не говорим, че ако в някоя подпапка имаш symlink, сочещ към по-горна папка (например, почваш търсенето от /home/test и имаш symlink /home/test/symlink, сочещ към /home/test), ще изпаднеш в безкрайна рекурсия и ще зяпаш безкрайно повтаряща се информация, докато не убиеш ръчно скрипта. Има начин да се избегне, разбира се, но защо ти е да се вкарваш във филми, при цялото удобство и наличие на find във всички дистрибуции?
Активен

"Да си добре приспособен към болно общество не е признак за добро здраве" - Джиду Кришнамурти

villimon

  • Напреднали
  • *****
  • Публикации: 65
    • Профил
Re: shell script
« Отговор #28 -: Nov 01, 2013, 18:17 »
Всичко го правя с образователна чел да овладея това онова. Естествено съм съгласен с теб, че тия работи са безсмислени след като има команди като tree и find които освен всичко са оптимизирани. Ще се мъча докато не получа резултат.
Активен

neter

  • Global Moderator
  • Напреднали
  • *****
  • Публикации: 3408
  • Distribution: Debian, SailfishOS, CentOS
  • Window Manager: LXDE, Lipstick
    • Профил
    • WWW
Re: shell script
« Отговор #29 -: Nov 01, 2013, 21:43 »
Оу, бях останал с впечатлението, че просто търсим нещо, с което да се свърши някаква конкретна работа. Щом е с образователна цел, тогава всичко се променя - много ми харесва скриптът ти в такъв случай :)
Сега, първо някои препоръки в сегашния му вид:
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):
  1. #!/bin/bash
  2.  
  3. filefind ()
  4. {
  5.    for i in *; do
  6.        if [ -d "$i" ]; then
  7.            j=1
  8.            while [ "$j" -le "$var" ]; do
  9.                printf "    "  
  10.                j=$(( j + 1 ))
  11.            done
  12.            echo "$i"
  13.            cd "$i"
  14.            var=$(( var + 1 ))
  15.            filefind
  16.        fi  
  17.    done
  18.    var=$(( var - 1 ))
  19.    cd ..
  20. }
  21.  
  22. cd "$1"
  23.  
  24. var=0
  25.  
  26. filefind

Сега, за добавянето на изпълнимите файлове към изведения списък. Тук отново имаме двата варианта, спрямо това кои изпълними файлове искаш да се извеждат - тези, които потребителят, изпълнил скрипта, може да изпълнява, или всички файлове, съдържащи бит за изпълнение в някоя от групите права.

Пример за варианта, при който се извеждат само файловете, които потребителят, изпълнил скрипта, може да изпълнява:
Код
GeSHi (Bash):
  1. #!/bin/bash
  2.  
  3. filefind ()
  4. {
  5.    for i in *; do
  6.        if [[ (-d "$i" && -x "$i" && ! -h "$i") || (-f "$i" && -x "$i") ]]; then
  7.            j=1
  8.            while [ "$j" -le "$var" ]; do
  9.                printf "    "  
  10.                j=$(( j + 1 ))
  11.            done
  12.            if [ -d "$i" ]; then
  13.                echo "$i/"
  14.                cd "$i"
  15.                var=$(( var + 1 ))
  16.                filefind
  17.            else
  18.                echo "$i"
  19.            fi  
  20.        fi  
  21.    done
  22.    var=$(( var - 1 ))
  23.    cd ..
  24. }
  25.  
  26. cd "$1"
  27.  
  28. var=0
  29.  
  30. filefind
Обърни внимание, че съм добавил различно echo, спрямо това дали е файл или директория, за да се различават по някакъв начин в списъка после. Може да си добавиш и други различаващи знаци, ако искаш. Може и да премахнеш разликата, но не те съветвам. А проверките в if-а на ред 6 станаха много, заради защитите от проби за листване на рекурсивни symlink-ове (онези, за които в предния пост ти писах, че ще ти създадат проблеми) и листване на папки, за които потребителят няма права да ги листва (което също би довело до безкраен цикъл).

Пример за варианта, при който се извеждат всички файлове, съдържащи бит за изпълнение в някоя от групите права:
Код
GeSHi (Bash):
  1. #!/bin/bash
  2.  
  3. filefind ()
  4. {
  5.    for i in *; do
  6.        if [[ (-d "$i" && -x "$i" && ! -h "$i") || (-f "$i" && "$(stat -c %A "$i" 2>/dev/null | grep '[x|s|t]')") ]]; then
  7.            j=1;
  8.            while [ "$j" -le "$var" ]; do
  9.                printf "    "  
  10.                j=$(( j + 1 ))
  11.            done
  12.            if [ -d "$i" ]; then
  13.                echo "$i/"
  14.                cd "$i"
  15.                var=$(( var + 1 ))
  16.                filefind
  17.            else
  18.                echo "$i"
  19.            fi  
  20.        fi  
  21.    done
  22.    var=$(( var - 1 ))
  23.    cd ..
  24. }
  25.  
  26. cd "$1"
  27.  
  28. var=0
  29.  
  30. filefind
Тук използваме командата stat, за да изведем пълния списък от права на съответния файл или папка. Да не те притеснява, малък инструмент е и го има във всяка дистрибуция. В grep съм описал търсене не само на "x" правило, но и на "s" и "t" правило, за да покрием случаите, когато, освен бит за изпълнение, към съответната група права поради някаква причина е зададено и някое от специалните права SUID (ще имаме "s" вместо "x" в правата за потребителя-собственик), SGID (ще имаме "s" вместо "x" в правата за групата-собственик) и sticky bit (ще имаме "t" вместо "x" в правата за други). Ако някое от тези специални права е зададено, но в съответната група права нямаме зададен бит за изпълнение, тогава буквите им биха били големи ("S" и "T"), така че нямаме проблем с това, както сме описали малки букви в grep и не сме задали да не прави разлика между малки и големи букви.

Разбира се, в скрипта може да се обединят и двата варианта на търсене и с аргумент към скрипта потребителят да си избира дали да търси само файловете, които може да изпълнява, или да търси всички файлове, които имат бит за изпълнение в някоя от групите права. Оставям на теб да го направиш, ако ти се занимава, че и без това постът ми стана много дълъг :)
« Последна редакция: Nov 01, 2013, 22:25 от neter »
Активен

"Да си добре приспособен към болно общество не е признак за добро здраве" - Джиду Кришнамурти

Подобни теми
Заглавие Започната от Отговора Прегледи Последна публикация
rc.d shell script
Настройка на програми
VlasA 3 2802 Последна публикация Aug 29, 2004, 12:05
от VlasA
Shell-script- за минаване от един юзър в друг
Настройка на програми
Nik123 5 3514 Последна публикация Jul 03, 2006, 20:22
от Nik123
shell script с параметри
Общ форум
k0tka 1 2824 Последна публикация May 25, 2012, 20:23
от k0tka
ПРЕМЕСТЕНО: shell script
Общ форум
neter 0 1886 Последна публикация Oct 18, 2013, 22:59
от neter
shell script за newuser
Общ форум
theshit 6 2695 Последна публикация May 11, 2014, 22:02
от go_fire