Я только что случайно узнал, что в bash можно присвоить команду переменной без использования alias
.
g=date
$g
Mon Jun 27 13:00:40 MYT 2016
Это работает. Вот еще пример:
jj="ping yahoo.com"
$jj
PING yahoo.com (98.138.253.109) 56(84) bytes of data.
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=1 ttl=41 time=347 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=2 ttl=41 time=345 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=3 ttl=41 time=345 ms
Я использую эту версию bashbash --version GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Я посмотрелстекобмениtldp абс, но не нашел, что мы можем сделать это так. Так это новые возможности bash или что-то, что упускается из виду? Это считаетсязамена команды?
решение1
При интерактивном использовании оболочка считывает строки ввода с терминального устройства. После ввода строки онапроанализированоразделившись нажетоны(слова и операторы). Затем токены или слова расширяются или разрешаются в определенном порядке.
Примечание: в целом, лучше ссылаться на канонический источник информации, такой как проектная документация или отраслевая спецификация, а не на источники из вторых рук, такие как Advanced Bash-Scripting Guide, онлайн-уроки, книги – или даже Stack Exchange :). Такие источники из вторых рук полезны для введения и объяснения концепций на более простом языке, но они обычно не предназначены для полноты или замены официальной документации. Информация в источниках из вторых рук также может быть устаревшей.
В этом случаеСпецификация POSIX для анализа простых командговорится, что
- Слова, которые не являются переменными назначениями или перенаправлениями, должны быть расширены. Если после их расширения остаются какие-либо поля, первое поле должно считаться именем команды, а остальные поля — аргументами для команды.
TheРаздел руководства Bash о простом расширении командтакже говорится, что
- Слова, которые не являются присвоениями переменных или перенаправлениями, расширяются (см. Shell Expansions). Если после расширения остаются какие-либо слова, первое слово принимается за имя команды, а остальные слова — за аргументы.
решение2
Это не замена команды, этопеременнаяподстановка. Вы не присваиваете команду переменной, вы присваиваете строку. Команда выполняется, когда вы используете переменную, а не во время присваивания.
g=date
сохраняет строку date
в переменной g
. Если вы затем запустите echo "$g"
, это выведет значение g
, т.е. date
(с последующей новой строкой), поскольку значение g
передается команде echo
как первый аргумент. Если вы запустите "$g"
, это поместит строку date
в первую позицию команды, то есть это имя команды.
С $jj
, в игру вступает второй фактор. Поскольку расширение переменной находится вне кавычек,«оператор split+glob»применяется к значению. В данном случае это означает, что значение jj
разбивается на два слова, разделенных пробелом. Таким образом, слово ping
оказывается в командной позиции, а слово yahoo.com
является первым аргументом.
решение3
Это ожидаемое поведение, и оно работает уже много лет. Это полезно для построения команд в скриптах.
Например, иногда мне следует применить декомпрессию к некоторым входным данным перед отправкой их в конвейер (и сжатие к выходным данным после этого), а иногда — нет. Использование bash
:
if (( use_compression == 1 )); then
infilter='gzip -d -c'
outfilter='gzip -c'
else
infilter='cat'
outfilter='cat'
fi
$infilter "$indatafile" | somepipeline | $outfilter >"$outdatafile"
Это подстановка команд? Нет. «Подстановка команд» относится конкретно к замене $(...)
варианта с обратными кавычками содержимым его вывода.
Это вместо этогорасширение параметра, т.е. просто заменяет параметры их значениями. Это происходит до того, как команда фактически выполняется, поэтому это и работает.
Это означает, что такие команды, как следующие, также работают в командной строке:
$ decompress='gzip -d -c'
$ ${decompress/g/gun/} filename >unzippedfilename
(который будет выполняться gunzip
вместо gzip
)
РЕДАКТИРОВАТЬ:О псевдонимах.
В bash
руководстве говорится:
Почти для всех целей псевдонимы заменяются функциями оболочки.
... и я согласен.
Псевдонимы хороши для коротких вещей, таких как
alias ls="ls -F"
(это единственный псевдоним, который у меня есть в моих собственных сеансах оболочки)
Вероятно, вы не хотите использовать расширения параметров для "псевдонимов" команд в командной строке. Если только это не больно печатать. Расширение параметров также не позволяет выполнять немного более сложные задачи, такие как конвейеризация.
Если вам регулярно приходится выполнять операции средней сложности, используйте для них функции оболочки.
Взяв пример из принятого ответа навопрос U&L(ссылку на которую вы дадите в комментариях ниже):
alias my_File='ls -f | grep -v /'
Этот псевдоним, очевидно, работает, но использование
my_File='ls -f | grep -v /'
не сработает, если вы затем попытаетесь использовать его $my_File
в качестве команды в командной строке (как объяснено в теме U&L).
С помощью функции оболочки вы также сможете выполнять такие действия, как передача аргументов:
function my_File {
ls -l "$@" | fgrep -v '/'
}
$ my_File -iF symlink
84416642 lrwxr-xr-x 1 kk staff 4 Jun 27 09:03 symlink@ -> file
решение4
Это просто использование переменных оболочки — концепция, которая существовала и работала таким образом на протяжении десятилетий (без преувеличения).
Когда вы помещаете переменную в командную строку, оболочка подставляет ее, а затем выполняет команду, поэтому, если ваша переменная находится в начале, она, очевидно, будет рассматриваться как команда.