В Bash, когда исказить, когда написать сценарий, и когда записать функцию?

Из статьи в Википедии дистрибутивов Linux:

Дистрибутив Linux является членом семейства подобных Unix операционных систем, созданных сверху ядра Linux. Такими дистрибутивами (часто названный дистрибутивами, если коротко) являются Операционные системы включая большое количество приложений, такие как текстовые процессоры, электронные таблицы, медиаплееры и приложения базы данных.

То, что отличает их, является аппаратными средствами они supposrt, упаковка, патчи ядра, что устанавливает и версии приложений, они поставляют, их документация, устанавливают методы и т.д. Другие "классификации" - ориентированы ли они более к конечным пользователям или серверам.

Некоторые дистрибутивы (Debian, хинду, Fedora и другие) используются в качестве "начальной точки" для других дистрибутивов (Ubuntu получена из Debian, например). Это означает, что создатели, например, Sabayon Linux использовал хинду распределение, чтобы запустить их усилие по разработке и отслеживать эволюцию хинду в некоторой степени.

Можно посмотреть на страницу результатов поиска Distrowatch для этого вида примеров.

"ОСНОВАННЫЕ НА ОБ/МИН" дистрибутивы являются другой классификацией. Об/мин является системой управления пакета, не распределением. Некоторые дистрибутивы используют его (Redhat, и SuSe приходит на ум), непосредственно или через один из его frontends. Другие используют различные системы (pacman для Arch, перевозки для хинду). Система управления пакета является одним из важных различий между дистрибутивами.

Относительно версий нет никаких строгих критериев. Разработчики/менеджеры распределения выбирают то, что является присваивать версию/исправлять/новым программное обеспечение, которое они хотят включать в новую версию, полировать ее, и когда это готово, они поставляют ее. Нет последовательной схемы управления версиями через дистрибутивы.

Для Вашего последнего вопроса я не уверен, что понимаю, но Вы могли сказать, что Windows NT, 2000, XP, 2003/Vista, 2008 и Windows 7 является "версиями" Windows "распределение". И они - все в семействе Windows NT релизов Windows.

Таким образом, если Вы хотите провести параллель с дистрибутивами Linux, да, каждый, окна "выпуск" ближе к версии дистрибутива Linux. И происхождение "Windows NT" эквивалентно происхождению Redhat или SuSe, например.

(Одни из общих черт этих "происхождений" - то, что обычно существует главная версия ядра между релизами Windows, и это также имеет место для большого количества дистрибутивов Linux.)

367
25.04.2016, 23:01
14 ответов

Псевдоним не должен эффективно (в целом) делать больше, чем изменение опции по умолчанию команды. Это - не что иное как простая текстовая замена на названии команды. Это ничего не может сделать с аргументами, но передать их команде, которую это на самом деле выполняет. Таким образом, если просто необходимо добавить аргумент впереди единственной команды, псевдоним будет работать. Типичные примеры

# Make ls output in color by default.
alias ls="ls --color=auto"
# make mv ask before overwriting a file by default
alias mv="mv -i"

Функция должна использоваться, когда необходимо сделать что-то более сложное, чем псевдоним кроме этого не был бы полезен самостоятельно. Например, возьмите этот ответ по вопросу, который я спросил об изменении grepповедение по умолчанию в зависимости от того, является ли это в конвейере:

grep() { 
    if [[ -t 1 ]]; then 
        command grep -n "$@"
    else 
        command grep "$@"
    fi
}

Это - идеальный пример функции, потому что это слишком сложно для псевдонима (требующий различных значений по умолчанию на основе условия), но это не что-то, в чем Вы будете нуждаться в неинтерактивном сценарии.

Если Вы получаете слишком много функций или слишком больших функций, помещаете их в отдельные файлы в скрытом каталоге и получаете их в Вашем ~/.bashrc:

if [ -d ~/.bash_functions ]; then
    for file in ~/.bash_functions/*; do
        . "$file"
    done
fi

Сценарий должен стоять самостоятельно. Это должно иметь значение как что-то, что может снова использоваться или использоваться больше чем для одной цели.

245
27.01.2020, 19:28
  • 1
    Также важно помнить что – если не получено с . или source – сценарий выполняется отдельным процессом удара и имеет свою собственную среду. Поэтому что-либо, что изменяет среду оболочки (например, функции, переменные, и т.д.) не сохранится в среде оболочки, от которой Вы запускаете скрипт. –  Will Vousden 05.03.2015, 13:02

Только добавить несколько примечаний:

  • Только отдельный сценарий может использоваться с sudo (как то, если необходимо отредактировать системный файл), например:
sudo v /etc/rc.conf  #where v runs vim in a new terminal window;
  • Только псевдонимы или функции могли заменить системные команды под тем же именем (предполагающий добавление dir сценариев в конец ПУТИ который я думаю, желательно для безопасности в случае случайного или злорадного создания сценария с именем, идентичным системной команде), например:
alias ls='ls --color=auto'  #enable colored output;
  • Псевдонимы и функции берут меньше памяти и время для выполнения, но занимают время для загрузки (так как оболочка должна интерпретировать их всех прежде, чем показать, что Вы запрашиваете). Примите это во внимание при выполнении новых процессов оболочки regularily, например:
# pressing key to open new terminal
# waiting for a few seconds before shell prompt finally appears.

Кроме этого, Вы могли использовать самую простую возможную форму, т.е. сначала рассмотреть псевдоним, затем функционировать, затем сценарий.

3
27.01.2020, 19:28
  • 1
    Псевдонимы могут также использоваться с sudo. Но сначала Вам нужно alias sudo='sudo '. –  Mikel 09.05.2012, 18:32

Сценарий и псевдоним и сценарий и функция не являются взаимоисключающими. Вы можете и действительно хранить псевдонимы и функции в сценариях.

Сценарии являются просто кодом, который сделан персистентным. Полезные функции и псевдонимы, которые Вам нравится использовать в будущем, хранятся в сценариях. Однако сценарий часто является набором больше чем одной функции.

Так как псевдонимы не параметризованы, они очень ограничены; обычно определять некоторые параметры по умолчанию.

Функция является отдельной единицей кода, четко определенным понятием нескольких строк кода, которые не могут разделенный на меньшие, полезные части; тот, который может быть снова использован непосредственно или другой другими функциями.

7
27.01.2020, 19:28

По крайней мере частично это - вопрос персонального вкуса. С другой стороны, существуют некоторые ясные функциональные различия:

  • псевдонимы: только подходящий для простых текстовых замен, никаких аргументов/параметров
  • функции: легкий писать/использовать, полная поддержка сценариев оболочки, только доступный внутренний удар
  • сценарии: более или менее как функции, но доступный (вызываемый) за пределами удара также

Рассмотрение сценариев оболочки, я сделал последние несколько лет, которые я более или менее прекратил писать псевдонимам (потому что они все имеют тенденцию превращаться в функции со временем) и делает сценарии, только если они должны быть доступными также от сред неудара.

PS: что касается alias command="bash bashscriptname" Я на самом деле не вижу оснований, чтобы сделать это. Даже если bashscriptname не находится в $PATH, простом alias c=/path/to/script был бы достаточно.

15
27.01.2020, 19:28

Я думаю, что это до вкуса каждого человека. Для меня логика идет как это:

  • Сначала я пытаюсь сделать псевдоним, потому что это является самым простым.
  • Если вещь является слишком сложной для помещений в одну строку, я пытаюсь сделать ее функцией.
  • Когда функция начинает расти вне дюжины строк, я поместил ее в сценарий.

Нет действительно ничего для ограничения Вас в выполнении чего-то, что работает.

38
27.01.2020, 19:28
  • 1
    я часто пропускаю функциональную опцию и делаю сценарий сразу же. Но я соглашаюсь, что это - частично вопрос вкуса –  Bernhard 05.02.2012, 17:00
  • 2
    функция начинает иметь смысл при необходимости в нем в нескольких сценариях. –  Nils 10.02.2012, 23:45
  • 3
    ... или если Вам нужны побочные эффекты изменить текущую оболочку. –  glenn jackman 27.07.2015, 19:30

Еще одна вещь, которой я не верю, была поднята: функция выполняется в контексте процесса вызова, тогда как сценарий разветвляет новую оболочку.

Это могло быть важно для производительности - функция быстрее, так как она не делает fork() и exec(). При нормальных обстоятельствах различие тривиально, но если Вы отлаживаете систему, которая является вне памяти и является перегрузкой страницы, это могло иметь большое значение.

Кроме того, если Вы хотите изменить свою текущую среду оболочки, необходимо использовать функцию. Например, функция могла изменить поиск команды $PATH для текущей оболочки, но сценария не может, потому что она воздействует на копию ветвления/должностного лица $PATH.

9
27.01.2020, 19:28

Другие ответы предоставляют некоторые мягкие общие руководящие принципы на основе персонального вкуса, но игнорируют много подходящих тех, что нужно рассмотреть при решении между сценариями, функциями или псевдонимами.

Псевдонимы и функции ¹

  • Все содержание псевдонимов и функций хранится в памяти оболочки.
  • Естественным следствием этого являются псевдонимы, и функции могут только использоваться текущей оболочкой, а не любыми другими программами, которые можно вызвать от оболочки как текстовые редакторы, сценарии или даже дочерние экземпляры той же оболочки.
  • Псевдонимы и функции выполняются текущей оболочкой, т.е. они работают в и влияют на текущую среду оболочки. ² Никакой отдельный процесс необходимо для выполнения псевдонима или функции.

Сценарии

  • Оболочки не сохраняют сценарии в памяти. Вместо этого сценарии прочитаны из файлов, где они хранятся каждый раз, когда они необходимы. Если сценарий найден через a $PATH поиск, много оболочек хранят хеш его пути в памяти, чтобы сэкономить время на будущем $PATH поиски, но это - степень объема потребляемой памяти сценария, если не используемого.
  • Сценарии могут быть вызваны большим количеством способов, чем функции и псевдонимы могут. Они могут быть переданы как аргумент интерпретатору, как sh script, или вызванный непосредственно как исполняемый файл, в этом случае интерпретатор в строке хижины (например. #!/bin/sh) вызывается для выполнения его. В обоих случаях скрипт запущен отдельным процессом интерпретатора с его собственной средой, отдельной от той из Вашей оболочки, на среду которой сценарий не может влиять всегда. Действительно, оболочка интерпретатора даже не должна соответствовать оболочке вызова. Поскольку сценарии вызвали этот путь, кажется, ведут себя как любой обычный исполняемый файл, они могут использоваться любой программой.

    Наконец, скрипт может быть прочитан и запущен текущей оболочкой с ., или в некоторых оболочках, source. В этом случае сценарий ведет себя во многом как функция, которая читается по запросу вместо того, чтобы быть постоянно сохраненной в памяти.

Приложение

Учитывая вышеупомянутое, мы можем придумать некоторые общие руководящие принципы для того, сделать ли что-то сценарием или функцией / псевдоним.

  • Другие программы помимо Вашей оболочки должны смочь использовать его? Если так, это должен быть сценарий.

  • Вы только хотите, чтобы это было доступно от интерактивной оболочки? Распространено хотеть изменить поведение по умолчанию многих команд, когда выполнено в интерактивном режиме, не влияя на внешние команды / сценарии. Для этого случая используйте псевдоним / функциональный набор в "единственном интерактивным режимом" емкостно-резистивном файле оболочки (для bash это .bashrc).

  • Это должно изменить среду оболочки? Оба функция / псевдоним или полученный сценарий являются возможным выбором.

  • Это - что-то, что Вы часто используете? Вероятно, более эффективно сохранить его в памяти, поэтому сделайте это функцией / псевдоним, если это возможно.

  • С другой стороны это - что-то, что Вы используете только редко? В этом случае нет никакого смысла, имеющего его память пожирателя ресурсов, когда Вам не нужен он, поэтому сделайте это сценарием.


¹, В то время как функции и псевдонимы имеют некоторые важные различия, они группируются, потому что функции могут сделать все, что псевдонимы могут. Псевдонимы не могут иметь локальных переменных, и при этом они не могут обработать аргументы, и они неудобны для чего-либо дольше, чем одна строка.

² Каждый рабочий процесс в системе Unix имеет среду, состоящую из набора variable=value пары, которые часто содержат глобальные параметры конфигурации, как LANG для локали по умолчанию и PATH для определения исполняемого пути поиска.

265
27.01.2020, 19:28
  • 1
    По моему скромному мнению, Это - лучший ответ. –  Luc M 08.02.2012, 20:51
  • 2
    Формат вопроса/ответа является прекрасной идеей. Я мог бы украсть это. ;-) –  Mikel 09.05.2012, 18:46
  • 3
    Стоящий замечания: если два (или больше) сценарии должны совместно использовать некоторый код, вероятно, лучше поместить тот код в функцию, которая самостоятельно расположена в третьем файле, который импортируют/получают оба из тех сценариев. –  kbolino 21.09.2016, 22:40
  • 4
    Другой объект для добавления к тому списку вопросов: необходимо ли когда-либо изменять функциональность в команде на лету? изменения в сценарии будут отражены на всех сессиях, тогда как функции и псевдонимы должны быть перезагружены или переопределены на на основание сессии. –  Stratus3D 15.04.2017, 00:02
  • 5
    Хороший ответ. Еще одна важная вещь (для меня): при создании "ярлыка" на другой utils лучше использовать псевдоним, потому что существующее автоматическое заполнение будет просто работать с псевдонимами, но не со сценариями или функциями (так +1 для псевдонимов). например, Путем создания alias g='gradle' Я получаю gradle автозавершение при использовании моего g псевдоним, но не получит его out-of-the-box при использовании сценария с gradle $* или функция с gradle $@ –  Yoav Aharoni 04.02.2018, 16:29

Если это должно быть очень быстро, сделайте это псевдонимом или функцией.

Если это должно быть применимо вне Вашей предпочтительной оболочки, сделайте это сценарием 1

Если это берет аргументы, сделайте это функцией или сценарием.

Если это должно содержать специальные символы, сделайте это псевдонимом или сценарием 2

Если это должно работать с sudo, сделайте это псевдонимом или сценарием 3

Если Вы хотите изменить его легко без того, чтобы выходить и зашедшего, сценарий легче 4

Сноски

1 Или делают это псевдонимом, вставляют его ~/.env и набор export ENV="$HOME/.env", но это сложно, чтобы заставить его работать портативно.

2 Имени функций должны быть идентификаторами, таким образом, они должны начаться с буквы и могут только содержать буквы, цифры и символы нижнего подчеркивания. Например, у меня есть псевдоним alias +='pushd +1'. Это не может быть функция.

3 И добавляют псевдоним alias sudo='sudo '. Так же любая другая команда такой как strace, gdb, и т.д. это принимает управление как его первый аргумент.

4 См. также: fpath. Конечно, можно также сделать source ~/.bashrc или подобный, но это часто имеет другие побочные эффекты.

5
27.01.2020, 19:28
  • 1
    я не знал Вас, мог исказить + в ударе. Интересно, после тестирования я обнаружил, что в ударе можно сделать + псевдоним, но не функция, как Вы говорите, но zsh, является реверсом - + может быть функция, но не псевдоним. –  Kevin 09.05.2012, 21:42
  • 2
    В zsh необходимо записать alias -- +='some command here'. –  Mikel 10.05.2012, 04:07
  • 3
    Так или иначе я не думаю, искажая + является портативным. Посмотрите спецификацию POSIX на Именах Псевдонима –  jw013 23.08.2012, 21:08
  • 4
    Upvote для покрытия sudo использование. Относительно сноски 4 я храню свои псевдонимы в ~/.bash_aliases и функциональные определения в ~/.bash_functions таким образом, я могу легко реsource их (без любой опасности побочных эффектов). –  Anthony G - justice for Monica 19.11.2015, 13:15

Когда записать сценарий...

  • Сценарии собирают компоненты программного обеспечения (иначе. инструменты, команды, процессы, исполняемые файлы, программы) в более сложные компоненты, которые могут самостоятельно быть собраны в еще более сложные компоненты.
  • Сценарии обычно делаются исполняемым файлом, таким образом, они могут быть позваны по имени. При вызове новый подпроцесс порожден, чтобы сценарий работал в. Копии любого exportпеременные редактора и/или функции передаются значением сценарию. Изменения в тех переменных не распространяют назад к родительскому сценарию.
  • Сценарии могут также быть загружены (полученные), как будто они были частью сценария выполнения вызова. Это походит на то, что некоторый другой вызов языков "импортируют" или "включают". При определении источника они выполняются в рамках существующего процесса. Никакой подпроцесс не порожден.

Когда записать функцию...

  • Функции являются эффективно предварительно загруженными сценариями оболочки. Они работают немного лучше, чем вызов отдельного сценария, но только если он должен быть считан из механического диска. Сегодняшнее быстрое увеличение количества карт флэш-памяти, SSD и нормального кэширования Linux в неиспользованной RAM делает то улучшение в основном неизмеримым.
  • Функции служат принципиальными средствами удара достижения модульного принципа, инкапсуляции и повторного использования. Они улучшают ясность, надежность и пригодность для обслуживания сценариев.
  • Синтаксические правила для того, чтобы вызвать функцию идентичны функции вызова исполняемого файла. Функция с тем же именем как исполняемый файл была бы вызвана вместо исполняемого файла.
  • Функции локальны для сценария, в котором они находятся.
  • Функции могут быть экспортированы (скопированный значением), таким образом, они могут использоваться в названных сценариях. Таким образом функции только распространяют к дочерним процессам, никогда родители.
  • Функции создают допускающие повторное использование команды, которые часто собираются в библиотеки (сценарий только с функциональными определениями), чтобы быть полученными другими сценариями.

Когда записать псевдоним...

В рамках сценариев как сценарии библиотеки иногда псевдоним для функции необходим, такой как тогда, когда функция переименована, но обратная совместимость требуется. Это может быть выполнено путем создания простой функции со старым названием, которое передает все его аргументы новой функции...

# A bash in-script 'alias'
function oldFunction () { newFunction "$@"; }
10
27.01.2020, 19:28

Вот некоторые дополнительные моменты о псевдонимы и функции:

  • Одноименный псевдоним и функция могут сосуществовать
  • ищется пространство имен псевдонима сначала (см. первый пример)
  • псевдонимы не могут быть (не) установленным в подоболочках или неинтерактивной среде (см. второй пример)

Например:

alias f='echo Alias'; f             # prints "Alias"
function f { echo 'Function'; }; f  # prints "Alias"
unalias f; f                        # prints "Function"

Как мы видим, существуют отдельные пространства имен для псевдонимов и функций; более подробную информацию можно найти, используя declare -A -p BASH_ALIASES и declare -f f , которые выводят их определения (оба хранятся в памяти).

Пример, показывающий ограничения псевдонимов:

alias a='echo Alias'
a        # OK: prints "Alias"
eval a;  # OK: prints "Alias"
( alias a="Nested"; a );  # prints "Alias" (not "Nested")
( unalias a; a );         # prints "Alias"
bash -c "alias aa='Another Alias'; aa"  # ERROR: bash: aa: command not found

Как мы видим, псевдонимы не являются вложенными, в отличие от функций. Также их использование ограничено интерактивными сессиями.

Наконец, обратите внимание, что вы можете выполнять произвольные вычисления в псевдониме, объявив функцию a, немедленно вызывающую ее, например:

alias a_complex_thing='f() { do_stuff_in_function; } f'

, которая уже широко используется в случае псевдонимов Git. Преимущество этого по сравнению с объявлением функции состоит в том, что ваш псевдоним не может быть просто перезаписан исходным (или использованием . ) сценария, который объявляет одноименную функцию.

11
27.01.2020, 19:28

Мое правило:

  • aliases - одна команда, без параметров
  • functions - одна команда, несколько параметров
  • script - несколько команд, без параметров
2
27.01.2020, 19:28

В многопользовательской (или многосисячной) среде я использую скрипты для всего, даже если это просто короткая обертка 'exec something....'.

Конечно, технически это медленнее/менее эффективно, чем псевдоним или функция, но это почти никогда не имеет значения - и если скрипт находится в пути, он всегда работает.

Ваша функция может быть вызвана из cron, из чего-то с урезанным или измененным окружением, таким как sudo или env, или пользователь может просто использовать другой shell, чем вы - все это может привести к поломке псевдонима или функции.

Если у вас есть что-то чувствительное к производительности, обрабатывайте это как особый случай, или, что еще лучше, считайте это триггером для переписывания на более функциональном языке сценариев.

Если мы говорим о функциях, которые будут использоваться только в других сценариях, то вы также можете рассмотреть возможность определения стандартной оболочки и написания сценария библиотеки функций, который может быть использован во всех других сценариях.

T

1
27.01.2020, 19:28

Пример ситуации, в которой вы, скорее всего, хотели бы использовать псевдоним.

Я знаю, что это старый пост, но я хотел бы указать на ситуацию, когда мне почти пришлось использовать комбинацию псевдонима со сценарием, и я решил не использовать функцию.

У меня есть сценарий в ~ / .bin / под названием setup , который выполняет следующие действия: 1

  1. переводит меня в определенный каталог.
  2. определяет несколько переменных.
  3. печатает сообщения о состоянии каталога. 2

Дело в том, , что если бы я просто запустил setup , у меня бы не были определены эти переменные, и я бы не попал в каталог по адресу все. Лучшим решением, которое я нашел, было добавить этот сценарий в PATH и добавить alias setup = ". ~ / .Bin / setup" в ~ / .bashrc или что-то еще.

Примечания:

  1. Я использовал сценарий для этой задачи, а не функцию не потому, что он очень длинный, а потому, что я могу его редактировать, и мне не нужно исходить из файла после редактирования, если я хочу обновить его использование .
  2. Похожий случай случился со мной, когда я создал скрипт для перезагрузки всех моих точечных файлов. 3
  1. Сценарий доступен в моем репозитории файлов точек в папке .bin / .
  2. О сценарии : Я даю этому сценарию аргумент, который является именем проекта, который я определил в расширенном режиме. Впоследствии сценарий знает, что нужно привести меня в нужный каталог в соответствии с определенным файлом csv . Переменные, которые он определяет, берутся из make-файла в этом каталоге. Затем сценарий запускается ls -l и git status , чтобы показать мне, что там происходит.
  3. Этот сценарий также доступен в моем репозитории dotfiles под .bin / .
0
20.08.2021, 13:29

Я могу прокомментировать только свое личное использование псевдонимов (, особенно если вы медленно работаете с клавиатурой, как я. Или не может коснуться типа. Тоже как я )Мне гораздо проще использовать псевдонимы для захвата редко используемых, но сложных команд, особенно таких, как:
alias dockpurge='docker rmi $(docker images | grep "^<none>" | awk "{print $3}")'
которым я редко пользуюсь, но никто -и -менее не находит полезным.
Или даже часто используемые команды, которые мне проще связать с несколькими нажатиями клавиш, такими как:
alias mcpi='mvn clean compile package install'
потому что я такой ленивый :)Если подытожить, то использование псевдонима является личной комбинацией собственного здравого смысла и личного вкуса(лучших практик несмотря на ).

0
20.08.2021, 13:29

Теги

Похожие вопросы