Чому вбудовані оболонки не мають належних сторінок?


32

Усі вбудовані оболонки мають однакову сторінку вручну:

BUILTIN(1)                BSD General Commands Manual               BUILTIN(1)

NAME
     builtin, !

тощо.

Потім є невеликий текст, що описує, що таке вбудовані оболонки, а потім список, який виглядає приблизно так:

  Command       External    csh(1)    sh(1)
       !             No          No        Yes
       %             No          Yes       No

Але якщо ми це робимо, man grepми отримуємо такі розділи, як

  • Клопи
  • Історія
  • Дивись також
  • Стандарти
  • Опис

тощо.

Чи не вбудовані оболонки мають власну історію, опис та аргументи на кшталт -Aабо -r? Чому це не передбачено на сторінках керівництва, і як я навчився б їх правильно та ефективно використовувати?


Відповіді:


25

Тому що вбудовані є частиною оболонки. Будь-які помилки або історія у них є помилками та історією самої оболонки. Вони не є незалежними командами і не існують поза оболонкою, в яку вони вбудовані.

Еквівалентом, bashпринаймні, є helpкоманда. Наприклад:

$ help while
while: while COMMANDS; do COMMANDS; done
    Execute commands as long as a test succeeds.

    Expand and execute COMMANDS as long as the final command in the
    `while' COMMANDS has an exit status of zero.

    Exit Status:
    Returns the status of the last command executed.

Усі вбудовані в bash helpсторінки. Навіть helpсама:

$ help help
help: help [-dms] [pattern ...]
    Display information about builtin commands.

    Displays brief summaries of builtin commands.  If PATTERN is
    specified, gives detailed help on all commands matching PATTERN,
    otherwise the list of help topics is printed.

    Options:
      -d    output short description for each topic
      -m    display usage in pseudo-manpage format
      -s    output only a short usage synopsis for each topic matching
        PATTERN

    Arguments:
      PATTERN   Pattern specifiying a help topic

    Exit Status:
    Returns success unless PATTERN is not found or an invalid option is given.

Натхненний сценарієм @ mikeserv sed, ось невелика функція, яка надрукує відповідний розділ чоловічої сторінки за допомогою Perl. Додайте цей рядок до файлу ініціалізації оболонки ( ~/.bashrcдля bash):

manperl(){ man "$1" | perl -00ne "print if /^\s*$2\b/"; }

Потім ви запускаєте її, надаючи довідкову сторінку та назву розділу:

$ manperl bash while
       while list-1; do list-2; done
       until list-1; do list-2; done
              The while command continuously executes the list list-2 as long as the last command in the list list-1 returns an exit
              status of zero.  The until command is identical to the while command, except that the test is negated; list-2 is  exe‐
              cuted  as  long  as the last command in list-1 returns a non-zero exit status.  The exit status of the while and until
              commands is the exit status of the last command executed in list-2, or zero if none was executed.

$ manperl grep SYNOPSIS
SYNOPSIS
       grep [OPTIONS] PATTERN [FILE...]
       grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]

$ manperl rsync "-r"
       -r, --recursive
              This tells rsync to copy directories recursively.  See also --dirs (-d).

2
@DisplayName вони є Баш. Вони є його частиною і так, вони пояснені в SHELL BUILTIN COMMANDSрозділі bashдовідкової сторінки. Їх "чоловічі сторінки" є help builtin_name.
тердон

3
Що незрозуміло - це те, чому їм не надавались довідкові сторінки. Сторінки людини - це лише файли на MANPATH. Вони не повинні відповідати окремим бінарним файлам. В принципі немає жодної причини, чому bash не міг би відправляти сторінки зі своїми підручниками, а не мати внутрішню систему допомоги.
Френсіс Деві

4
@FrancisDavey: Але більшість вбудованих існує (з різним розширенням) в різних оболонках. Упорядкування не мають специфічних оболонок; вони загальносистемні.
rici

2
@FrancisDavey Як сказав Rici, команди не є системними. Було б трохи вводить в оману , щоб мати довідкову сторінку для команди, це не присутній в кожній оболонці, але ще гірше, це було б дуже заплутаним , щоб мати довідкову сторінку для команди, яка присутня в декількох оболонок, але поводиться по- різному (наприклад , , приймає різні аргументи, має різний синтаксис тощо).
Джошуа Тейлор

1
@mikeserv Однак я хотів би побажати довідкових сторінок для вбудованих оболонок відповідно до того, що, наприклад, пропонує git, де man git commitвідкривається довідкова сторінка git-commit. Щось подібне man bash ifбуло б чудово .
Джошуа Тейлор

5

Хоча це правда , що деякі вбудовані команди оболонок можуть мати убогий показ в повному підпорядкуванні - особливо для тих bashПевних вбудованих команд , які ви тільки ймовірно, використання в системі GNU (GNU на людях, як правило, не вірять в manі віддайте перевагу власним infoсторінкам) - переважна більшість утиліт POSIX - вбудовані оболонки чи інше - дуже добре представлені в Посібнику програміста POSIX.

Ось уривок з нижньої частини мого (який, мабуть, триває приблизно man sh 20 сторінок ...)

введіть тут опис зображення

Всі ті , є й інші , які не йдеться , такі як set, read, break... ну, мені не потрібно , щоб назвати їх усіх. Але зверніть увагу (1P)на праворуч внизу - воно позначає посібник серії POSIX категорії 1 - це manсторінки, про які я говорю.

Можливо, вам просто потрібно встановити пакет? Це виглядає перспективно для системи Debian. Хоча helpце корисно, якщо ви зможете його знайти, ви обов'язково отримаєте цю POSIX Programmer's Guideсерію. Це може бути надзвичайно корисно. І це складові сторінки дуже докладно.

Окрім цього, вбудовані оболонки майже завжди перераховані в конкретному розділі посібника з конкретних оболонок. zshнаприклад, для цього є ціла окрема manсторінка - (я думаю, що це загальна кількість 8 або 9 окремих zshсторінок - включаючи zshallякі величезні.)

Ви можете grep manзвичайно:

man bash 2>/dev/null | 
grep '^[[:blank:]]*read [^`]*[-[]' -A14

   read [-ers] [-a aname] [-d  delim]  [-i  text]  [-n
   nchars]  [-N  nchars]  [-p prompt] [-t timeout] [-u
   fd] [name ...]
          One line is read from the standard input, or
          from  the  file descriptor fd supplied as an
          argument to the -u  option,  and  the  first
          word is assigned to the first name, the sec‐
          ond word to the second name, and so on, with
          leftover words and their intervening separa‐
          tors assigned to the last  name.   If  there
          are  fewer  words read from the input stream
          than names, the remaining names are assigned
          empty  values.   The  characters  in IFS are
          used to split the line into words using  the
          same  rules  the  shell  uses  for expansion

... що досить близько до того, що я робив під час пошуку оболонки man. Але в більшості випадків helpце досить добре bash.

Я фактично працював над sedсценарієм, щоб обробляти подібні речі останнім часом. Так я схопив розділ на малюнку вище. Це ще довше, ніж мені подобається, але вдосконалюється - і може бути досить зручно. У своїй нинішній ітерації він досить надійно витягне контекстно-чутливий розділ тексту у відповідності з заголовком розділу або підрозділу на основі [a] шаблону [s], поданого в командному рядку. Він забарвлює вихід і роздруковує до stdout.

Він працює, оцінюючи рівні відступів. Непорожні рядки введення, як правило, ігноруються, але коли він стикається з порожнім рядком, він починає звертати увагу. Він збирає рядки звідти до тих пір, поки не переконається, що поточна послідовність напевно відступає далі, ніж її перший рядок, перш ніж виникає інший порожній рядок, інакше він скидає нитку і чекає наступного порожнього. Якщо тест виявився успішним, він намагається зіставити лінію ведучого з його аргументами командного рядка.

Це означає, що відповідність шаблону відповідності:

heading
    match ...
    ...
    ...
        text...

..і ..

match
   text

..але не..

heading
    match
    match

    notmatch

.. або ..

         text

         match
         match
         text

         more text

Якщо відповідність може бути, вона починає друкувати. Він позбавить провідних пробілів відповідної лінії з усіх рядків, які він друкує - тому незалежно від рівня відступу, він виявив, що рядок на ній друкує так, ніби він знаходиться вгорі. Він буде продовжувати друкувати до тих пір, поки він не зустріне інший рядок на рівній або меншій мірі відступу, ніж його відповідна лінія - тому цілі розділи захоплюються лише збігом заголовка, включаючи будь-який / усі підрозділи, пункти, які вони можуть містити.

Отже, якщо ви попросите його відповідати шаблону, він зробить це лише у певній формі заголовка теми, а також забарвить і надрукує весь текст, який він знайде, у розділі на чолі зі збігом. Нічого не зберігається, окрім цього, окрім відступу першого рядка, - і це може бути дуже швидким та обробляти \nокремий вхід фактично будь-якого розміру.

Мені знадобилося деякий час, щоб зрозуміти, як повторно вписатись у підзаголовки, наприклад:

Section Heading
    Subsection Heading

Але я розібрався в підсумку.

Мені все-таки довелося переробити все заради простоти. Хоча раніше у мене було кілька невеликих циклів, які робили переважно ті самі речі дещо різними способами, щоб відповідати їхньому контексту, змінюючи засоби їх рекурсії, мені вдалося повторити копію більшості кодів. Зараз є дві петлі - один відбиток та один відступ чека. Обидва залежать від одного і того ж тесту - цикл друку починається, коли тест проходить, а цикл відступу переймається, коли він не працює або починається з порожнього рядка.

Весь процес проходить дуже швидко, тому що більшість часу він просто /./dвибирає будь-яку незаповнену лінію і переходить до наступної - рівномірний результат zshallмиттєвого заповнення екрана. Це не змінилося.

У всякому разі, поки що це дуже корисно. Наприклад, readщось вище можна зробити так:

mansed bash read

... і отримує цілий блок. Він може приймати будь-які шаблони чи будь-які, або декілька аргументів, хоча перший - це завжди manсторінка, на якій він повинен шукати. Ось малюнок деяких його результатів після того, як я зробив:

mansed bash read printf

введіть тут опис зображення

... обидва блоки повертаються цілими. Я часто його використовую так:

mansed ksh '[Cc]ommand.*'

... для яких це цілком корисно. Крім того, отримання SYNOPS[ES]робить його дуже зручним:

введіть тут опис зображення

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

mansed() {
MAN_KEEP_FORMATTING=1 man "$1" 2>/dev/null | ( shift
b='[:blank:]' s='[:space:]' bs=$(printf \\b) esc=$(printf '\033\[') n='\
' match=$(printf "\([${b}]*%s[${b}].*\)*" "$@")
sed -n "1p
    /\n/!{  /./{    \$p;d
        };x;    /.*\n/!g;s///;x
    :indent
        /.*\n\n/{s///;x
        };n;\$p;
        /^\([^${s}].*\)*$/{s/./ &/;h;   b indent
        };x;    s/.*\n[^-[]*\n.*//; /./!x;t
        s/[${s}]*$//;   s/\n[${b}]\{2,\}/${n} /;G;h
    };
    #test
    /^\([${b}]*\)\([^${b}].*\n\)\1\([${b}]\)/!b indent
        s//\1\2.\3/
    :print
    /^[${s}]*\n\./{ s///;s/\n\./${n}/
        /${bs}/{s/\n/ & /g;
            s/\(\(.\)${bs}\2\)\{1,\}/${esc}38;5;35m&${esc}0m/g
            s/\(_${bs}[^_]\)\{1,\}/${esc}38;5;75m&${esc}0m/g
            s/.${bs}//g;s/ \n /${n}/g
            s/\(\(${esc}\)0m\2[^m]*m[_ ]\{,2\}\)\{2\}/_/g
        };p;g;N;/\n$/!D
        s//./;  t print
    };
    #match
        s/\n.*/ /;  s/.${bs}//g
        s/^\(${match}\).*/${n}\1/
        /../{   s/^\([${s}]*\)\(.*\)/\1${n}/
        x;  s//${n}\1${n}. \2/; P
    };D
");}

Коротко, робочий процес такий:

  • будь-який рядок, який не є порожнім і не містить \nсимволу ewline, видаляється з виводу.
    • \nСимволи ewline ніколи не зустрічаються у просторі вхідного шаблону. Вони можуть мати місце лише в результаті редагування.
  • :printі :indentобидві взаємно залежні замкнуті петлі, і є єдиним способом отримання \nлінії виходу.
    • :printЦикл циклу починається, якщо провідними символами на рядку є ряд пробілів, за якими \nйде символ ewline.
    • :indentцикл починається з порожніх рядків - або на :printциклічних рядках, які виходять з ладу #test- але :indentвидаляє всі провідні \nпослідовності порожніх + евлайн зі свого результату.
    • Після того, як :printвін розпочнеться, він буде продовжувати тягнути вхідні лінії, знімати провідні пробіли до суми, знайденої на першому рядку в його циклі, переводити перескоку та підкреслювати втечу, що повертається в задній простір, на кольорові термінали та друкує результати, поки #testне виходить з ладу.
    • перед тим, як :indentпочати, спочатку перевіряє hстарий пробіл на предмет можливого продовження відступу (наприклад, підрозділ) , а потім продовжує виводити дані доти, доки #testне вдасться, і будь-який рядок, що слідує за першим, продовжує збігатися [-. Коли рядок після першого не відповідає цьому шаблону, він видаляється - і згодом всі наступні рядки до наступного порожнього рядка.
  • #matchі #testз'єднайте дві закриті петлі.
    • #testпроходить, коли провідна серія заготовок коротша за послідовність, за якою слідує остання \nлінія виходу в послідовності рядків.
    • #matchвипереджає провідні \nлінії ewlines, необхідні для початку :printциклу до будь-якої з :indentвихідних послідовностей, які ведуть із збігом будь-якого аргументу командного рядка. Ті послідовності, які не робляться порожніми, - і порожній рядок, що виходить, передається назад :indent.

2
Твій сед-фу сильний. Звичайно, ви можете зробити те саме, що manperl(){ man $1 | perl -00ne "print if /^\s*$2\b/"; }і тоді manperl sh SYNOPSISабо manperl sh read:)
terdon

@terdon - ні, ти не можеш. Це не їсть вхід. Я міг би зробити те саме, що, як sed 'H;$!d;g;s/\(\(\n *\)match\([^\n]*\)\2 \)\{1,\}\)*.\{,1\}/\1/g'і це, мабуть, що працює ..., але для цього потрібно проковтнути файл і проаналізувати його відразу. Це працює в потоці - він може обробляти введення будь-якого розміру за умови, що лінії не є астрономічно довгими. Він друкує , як це працює - і він розбирає всі man«s \backslash вислизає для завантаження. Але manце лише одна програма для цього - я багато чого застосував і для інших проблем ...
mikeserv

1
Я просто зачісую вашу ланцюжок, оскільки я можу робити те, що ви описуєте, за допомогою крихітного вкладиша. Однак зауважте, що він не проковтує файл цілим, він працює в потоці. Він просто визначає "лінії", використовуючи \n\nзамість, \nале все ж може обробляти будь-які розміри та друкувати, як це працює. Див. "Режим абзацу" тут: perldoc.perl.org/perlrun.html
terdon

@terdon Можливо, це був би кращий спосіб поїхати сюди. У sedньому можна зробити так: '/./{H;$!d' -e '};x;now work the paragraph...'. Я теж часто це роблю. Але я спочатку написав першу частину для перегляду журналу в прямому ефірі протягом необмеженої кількості часу, і навіть така поведінка була iffy - буфер може вибухнути за певних умов. Це була лише половина цього розміру - manускладнила його. Однак я переглянув, man -Hяк отримав manконспект вище, і думаю, що може бути простіше працювати з машинним HTML, який Groff може друкувати в системах GNU. Я свого роду лікоть уже
тигр

@terdon - Я вдруге здогадався і спробував підхід, орієнтований на абзаци, але простіше, як є. Це отримує розділи. Ніби mansed cmd DESCRIPTIONотримує розділ ОПИС - і всі включені. Зрівняний пошук друкується цілим і так, ніби його рівень відступу був першим. Він навіть пропускає помилкові позитиви, ігноруючи відповідні абзаци, але не відступаючи далі. Він відповідає своїм аргументам через кольоровий пробіл кольорів і не обробляє їх, поки не буде готовий до друку рядка. Все це мені дуже важко робити набагато більше даних, ніж один рядок за один раз.
mikeserv

1

Кожна оболонка має свій набір вбудованих. Хоча є спільні риси, у кожного вони є свої особливості, які потрібно задокументувати.

У таких системах, як Linux та FreeBSD (і OSX, яка успадковується від FreeBSD), де кожна оболонка надається як окремий пакет, немає вбудованої сторінки для вбудованих; натомість кожен вбудований документ задокументований на сторінці чоловічої оболонки. Тому прочитайте сторінку bash man для документації killвбудованого файлу bash , прочитайте сторінку "dash man" для документації killвбудованого тиру тощо. Існує також сторінка man для killавтономної утиліти.

Див. Чи можу я отримати індивідуальні сторінки для вбудованих команд bash? для manфункції, яка показує внутрішню документацію bash замість man сторінки, якщо аргументом є ім'я вбудованого.

Існують варіанти Unix, які надають підручні сторінки для вбудованих оболонок - насправді це більшість комерційних варіантів. Це можливо, оскільки система постачається або з однією оболонкою, або з набором відомих оболонок. На сторінці людини обговорюються відмінності між оболонками. Наприклад, fg(1)сторінка на Solaris 10 має секції для sh, kshі csh. Сторінка fg(1)man на AIX 7.1 посилається на «оболонку Korn» та «оболонку POSIX», але обговорює їх разом (вони, як правило, підтримують абсолютно однакові функції для fg). Сторінка fg(1)man на Tru64 5.0 обговорює вбудований ksh і посилає користувачів csh на csh(1)man. ШОСмабуть, йде з однією оболонкою. Ви можете встановити інші оболонки як додаткові пакети в цих операційних системах; якщо ви використовуєте власну оболонку, ви повинні пам’ятати, що підручні сторінки для вбудованих файлів не будуть відповідні при використанні оболонки, що не використовується за замовчуванням.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.