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

Мне потребовалось почти 10 лет использования Linux, чтобы задать этот вопрос. Это было все пробное и ошибочное и случайное ночное интернет-серфинг.

Но для этого людям не нужно 10 лет. Если бы я только начинал работать с Linux, я бы хотел знать: Когда псевдоним, когда сценарию и когда писать функцию?

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

alias houston='cd /home/username/.scripts/'

Это кажется очевидным. Но некоторые люди делают это:

alias command="bash bashscriptname"

(и добавьте его в файл .bashrc)

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

Потому что именно там я бы просто поместил что-то в свой PATH и chmod +x, это еще одна вещь, которая появилась после многих лет пробной и ошибки Linux.

Это приводит меня к следующей теме. Например, я добавил скрытую папку (.scripts/) в домашний каталог к ​​моей PATH, просто добавив строку в мой .bashrc (PATH=$PATH:/home/username/.scripts/), так что все исполняемые файлы автоматически автозаполняются.

Если мне нужно.

Мне это действительно не нужно, правда? Я бы использовал это только для языков, которые не являются оболочкой, например Python.

Если это оболочка, я могу просто написать функцию внутри того же .bashrc:

funcname () {
  somecommand -someARGS "[email protected]"
}

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

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

Но я что-то пропустил?

Итак, что бы вы сказали начальному пользователю Linux о том, когда нужно писать псевдоним, когда скрипту и когда писать функцию?

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

329 голосов | спросил ixtmixilix 5 FebruaryEurope/MoscowbSun, 05 Feb 2012 17:12:39 +0400000000pmSun, 05 Feb 2012 17:12:39 +040012 2012, 17:12:39

14 ответов


220

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

# 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 "[email protected]"
    else 
        command grep "[email protected]"
    fi
}

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

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

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

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

ответил Kevin 5 FebruaryEurope/MoscowbSun, 05 Feb 2012 23:00:14 +0400000000pmSun, 05 Feb 2012 23:00:14 +040012 2012, 23:00:14
229

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

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

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

Сценарии

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

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

Применение

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

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

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

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

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

  • И наоборот, это что-то, что вы используете редко? В этом случае нет смысла иметь его hog-память, когда она вам не нужна, поэтому сделайте это скриптом. р>


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

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

ответил jw013 6 FebruaryEurope/MoscowbMon, 06 Feb 2012 01:49:03 +0400000000amMon, 06 Feb 2012 01:49:03 +040012 2012, 01:49:03
32

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

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

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

ответил phunehehe 5 FebruaryEurope/MoscowbSun, 05 Feb 2012 18:52:59 +0400000000pmSun, 05 Feb 2012 18:52:59 +040012 2012, 18:52:59
14

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

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

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

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

ответил nohillside 5 FebruaryEurope/MoscowbSun, 05 Feb 2012 19:08:38 +0400000000pmSun, 05 Feb 2012 19:08:38 +040012 2012, 19:08:38
8

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

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

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

ответил Jan Steinman 8 FebruaryEurope/MoscowbWed, 08 Feb 2012 23:22:25 +0400000000pmWed, 08 Feb 2012 23:22:25 +040012 2012, 23:22:25
8

Когда писать скрипт ...

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

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

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

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

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

~/.bashrc
ответил DocSalvager 6 FebruaryEurope/MoscowbThu, 06 Feb 2014 15:29:32 +0400000000pmThu, 06 Feb 2014 15:29:32 +040014 2014, 15:29:32
6

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

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

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

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

ответил user unknown 6 FebruaryEurope/MoscowbMon, 06 Feb 2012 14:26:05 +0400000000pmMon, 06 Feb 2012 14:26:05 +040012 2012, 14:26:05
4

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

Если он должен использоваться вне вашей предпочтительной оболочки, сделайте это скриптом. 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 или подобное, но это часто имеет другие побочные эффекты.

ответил Mikel 9 Maypm12 2012, 19:44:51
4

Вот несколько дополнительных замечаний в отношении псевдонимов и функций:

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

Например:

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. Преимущество этого в том, чтобы объявить функцию, заключается в том, что ваш псевдоним нельзя просто перезаписать с помощью источника (или с помощью .) скрипта, который, как считается, объявляет одну и ту же функцию.

ответил leden 3 +03002015-10-03T23:25:05+03:00312015bEurope/MoscowSat, 03 Oct 2015 23:25:05 +0300 2015, 23:25:05
3

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

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

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

ответил corvinus 10 FebruaryEurope/MoscowbFri, 10 Feb 2012 20:37:10 +0400000000pmFri, 10 Feb 2012 20:37:10 +040012 2012, 20:37:10
2

Мое правило:

  • aliases - одна команда, без параметров
  • функции - одна команда некоторых параметров
  • script - несколько команд, без параметров
ответил Michael Durrant 10 ThuEurope/Moscow2015-12-10T05:00:39+03:00Europe/Moscow12bEurope/MoscowThu, 10 Dec 2015 05:00:39 +0300 2015, 05:00:39
1

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

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

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

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

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

Т

ответил tjb63 6 Jpm1000000pmWed, 06 Jan 2016 21:39:07 +030016 2016, 21:39:07
0

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

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

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

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

Точка , что если бы я просто запускал setup <project-name>, у меня не было бы этих переменных, и я бы не получил каталог вообще. Решение, которое я нашел лучшим, заключалось в том, чтобы добавить этот сценарий в PATH и добавить alias setup=". ~/.bin/setup" в ~/.bashrc или что-то еще.

Примечания:

  1. Я использовал сценарий для этой задачи, а не функцию не потому, что это особенно долго, но потому что я могу ее редактировать, и мне не нужно выводить файл после редактирования, если я хочу обновить его использование.
  2. Подобный случай меня уговорил, когда я создал скрипт для перезагрузки всех моих точечных файлов. 3
  
  1. Скрипт доступен в мой репозиторий dotfiles в .bin/.
  2.   
  3. О скрипте . Я даю этому скрипту аргумент, который является именем для проекта, который я определил в расширенном. Впоследствии скрипт знает, чтобы довести меня до нужного каталога в соответствии с определенным файлом csv. Определяемые переменные берутся из make-файла в этом каталоге. Скрипт запускается после ls -l и git status, чтобы показать мне, что там происходит.
  4.   
  5. Этот скрипт также доступен в моем репозитории dotfiles в разделе .bin/.
  6.   
ответил Doron Behar 25 PMpMon, 25 Apr 2016 22:32:42 +030032Monday 2016, 22:32:42
-8
  1. псевдоним для замены одного текста.
  2. скрипты для чего-то большего.
ответил eli 6 FebruaryEurope/MoscowbMon, 06 Feb 2012 09:16:10 +0400000000amMon, 06 Feb 2012 09:16:10 +040012 2012, 09:16:10

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132