Сценарии оболочки часто используются в качестве связующего звена для автоматизации и выполнения простых разовых задач. Какие из ваших любимых «скрытых» функций оболочки / языка сценариев Bash?
Смотрите также:





Использование инфиксных логических операторов
Рассмотрим простой, если:
if [ 2 -lt 3 ]
then echo "Numbers are still good!"
fi
Это выглядит некрасиво. Не очень современно. Если вы используете двойные скобки вокруг логического выражения, вы можете использовать обычные логические операторы!
if [[ 2 < 3 ]]
then echo "Numbers are still good!"
fi
madmath: Думаю, вы обнаружите, что [обычно является символической или жесткой ссылкой для тестирования, а [[- встроенной оболочкой. Он должен быть проанализирован оболочкой, иначе <будет выглядеть как перенаправление ввода.
Нет, «[» - это отдельная программа. '[[' не является
$ type [[[[- ключевое слово $ оболочки, которое [[$ # Нет вывода
По-видимому, SO не любит новые строки в комментариях, надеюсь, это не так уж сложно разобрать. Это было на Ubuntu с Bash 3.2.39, BTW.
[[ - это встроенная оболочка (< не будет работать с реальной командой, поскольку это будет интерпретироваться как перенаправление ввода). [ / test - это внешняя программа, но она перезаписывается в bash собственной встроенной программой.Используя арифметику:
if [[ $((2+1)) = $((1+2)) ]]
then echo "still ok"
fi
Удивительно, как много людей не знают этого и используют expr в своих скриптах.
Иногда достаточно арифметического расширения: ((2 + 1 == 1 + 2)) && echo OK
Я недавно прочитал Программирование на Csh считается вредным, который содержал этот поразительный драгоценный камень:
Consider the pipeline:
A | B | C
You want to know the status of C, well, that's easy: it's in $?, or $status in csh. But if you want it from A, you're out of luck -- if you're in the csh, that is. In the Bourne shell, you can get it, although doing so is a bit tricky. Here's something I had to do where I ran dd's stderr into a grep -v pipe to get rid of the records in/out noise, but had to return the dd's exit status, not the grep's:
device=/dev/rmt8
dd_noise='^[0-9]+\+[0-9]+ records (in|out)$'
exec 3>&1
status=`((dd if=$device ibs=64k 2>&1 1>&3 3>&- 4>&-; echo $? >&4) |
egrep -v "$dd_noise" 1>&2 3>&- 4>&-) 4>&1`
exit $status;
Вы хотите использовать переменную PIPESTATUS, которая представляет собой массив статусов выхода каждой команды в конвейере. $ {PIPESTATUS [0]} - это то, что вам нужно.
Стив, я никогда этого не знал - опубликуйте это как ответ здесь! (Я буду поддерживать, если вы это сделаете :)
Специальная переменная random:
if [[ $(($RANDOM % 6)) = 0 ]]
then echo "BANG"
else
echo "Try again"
fi
# [$ [$ RANDOM% 6] == 0] && rm -rf / || эхо «Ты живешь» :)
Нет необходимости в сигиле $ внутри арифметической оценки; нет необходимости в отдельной оценке и тестировании: if (( RANDOM % 6 == 0 )); then echo "BANG"; else echo "Try again"; fi Или даже короче: (( RANDOM % 6 )) && echo "Try again" || echo "BANG".
Мне нравится функция -x, позволяющая увидеть, что происходит в вашем скрипте.
bash -x script.sh
Почти все, что указано в разделе РАСШИРЕНИЕ в руководстве
В частности, расширение параметра:
$ I=foobar
$ echo ${I/oo/aa} #replacement
faabar
$ echo ${I:1:2} #substring
oo
$ echo ${I%bar} #trailing substitution
foo
$ echo ${I#foo} #leading substitution
bar
Отлично, вот как я получил% Ix = y% в cmd.exe ... :)
Массивы:
#!/bin/bash
array[0] = "a string"
array[1] = "a string with spaces and \"quotation\" marks in it"
array[2] = "a string with spaces, \"quotation marks\" and (parenthesis) in it"
echo "There are ${#array[*]} elements in the array."
for n in "${array[@]}"; do
echo "element = >>${n}<<"
done
Более подробную информацию о массивах (и других сложных сценариях bash) можно найти в Расширенное руководство по сценариям на Bash.
Вот два моих любимых:
Чтобы проверить синтаксис без реального выполнения сценария, используйте:
bash -n script.sh
Вернитесь в последний каталог (да, я знаю pushd и popd, но это быстрее)
cd -
«cd -» имеет то преимущество, что работает, если вы забыли поместить каталог в стек, но все же хотите вернуться туда.
Получить назад историю команд и аргументов
Можно выборочно получить доступ к предыдущим командам и аргументам с помощью оператора !. Это очень полезно, когда вы работаете с длинными путями.
Вы можете проверить свои последние команды с помощью history.
Вы можете использовать предыдущие команды, когда !<n> является n индексом команды в history, отрицательные числа отсчитываются в обратном порядке от последней команды в истории.
ls -l foo bar
touch foo bar
!-2
Вы можете использовать предыдущие аргументы с !:<n>, ноль - это команда,> = 1 - аргументы.
ls -l foo
touch !:2
cp !:1 bar
И то, и другое можно комбинировать с !<n>:<m>
touch foo bar
ls -l !:1 !:2
rm !-2:1 !-2:2
!-2
Вы также можете использовать диапазоны аргументов !<n>:<x>-<y>
touch boo far
ls -l !:1-2
Другие специальные модификаторы !:
* по всем аргументам
ls -l foo bar
ls !*
^ для первого аргумента (!:1 == !^)
$ для последнего аргумента
ls -l foo bar
cat !$ > /dev/null
Сочетание клавиш ^ R тоже очень удобно
Еще мне нравится alt- ^ (alt-shift-6 на американских клавиатурах). Он расширяет последовательности истории, такие как!: 2, чтобы вы могли видеть, что команда собирается делать, прежде чем запускать ее.
Вместо $! попробуйте набрать ESC +. Последний аргумент появится прямо под курсором.
Числовые выражения в стиле C:
let x = "RANDOM%2**8"
echo -n "$x = 0b"
for ((i=8; i>=0; i--)); do
let n = "2**i"
if (( (x&n) == n )); then echo -n "1"
else echo -n "0"
fi
done
echo ""
Обрезать содержимое файла (файл обнуления)
> file
В частности, это очень хорошо для усечения файлов журнала, когда файл открыт другим процессом, который все еще может записывать в файл.
чтобы предотвратить случайное обрезание файлов, set -o noclobber. Затем вам нужно использовать >| file для обрезки файла.
Обработка регулярных выражений
В последних выпусках bash реализовано сопоставление регулярных выражений, поэтому вы можете:
if [[ "mystring" =~ REGEX ]] ; then
echo match
fi
где REGEX - необработанное регулярное выражение в формате, описанном man re_format.
Совпадения из любых частей, заключенных в скобки, хранятся в массиве BASH_REMATCH, начиная с элемента 1 (элемент 0 - это согласованная строка целиком), так что вы также можете использовать это для синтаксического анализа с использованием регулярных выражений.
Как-то странно не заключать регулярное выражение в кавычки. . .
Встроенная подстановка команд:
hostname && dig +short $(hostname) && dig +short -x $(dig +short $(hostname))
Эта команда удобна для проверки RDNS на вашем почтовом сервере. :П
вставить последний параметр предыдущей строки
alt-. самая полезная комбинация клавиш, попробуйте и убедитесь, почему-то никто об этом не знает.
нажимайте ее снова и снова, чтобы выбрать более старые последние параметры.
отлично, когда вы хотите сделать что-то еще с тем, что вы использовали только мгновение назад.
Определенно +1. Спасибо за этот, такой полезный, но такой скрытый.
Могу я использовать Alt +. дать вам +2?
Я часто пользуюсь! $, Но это гораздо быстрее и полезнее.
Я считаю, что !$ слишком сложно печатать быстро. Я всегда должен сбавлять скорость и думать о том, чтобы поставить знак доллара на второе место. Alt + . быстрее и проще. Не говоря уже о том, что вы действительно видите текст перед его выполнением.
также вы можете переключаться между параметрами с помощью alt + - [0-9], а затем alt +.
Увидев параметр до вы облажаетесь и удалите все однозначно стоит.
Эта и другие комбинации волшебных клавиш в последующих ответах должны быть особенностями привязок readline emacs для bash. Я использую привязки vi, и они вообще не имеют никакого эффекта.
У этого есть отличный эквивалент. СТРЕЛКА ВВЕРХ (и СТРЕЛКА ВНИЗ для обратного направления). Если я чего-то не упускаю (здесь cygwin), я бы сказал нет и вместо этого просто использовал клавиши со стрелками.
@trinithis - это просто выбирает последний аргумент, а не всю последнюю команду, как это делает UP.
Если вы хотите, чтобы процесс продолжался после выхода из системы:
disown -h <pid>
- полезный встроенный в bash. В отличие от nohup, вы можете запустить disown в уже запущенном процессе.
Во-первых, остановите свою работу с помощью control-Z, получите pid от ps (или используйте echo $!), используйте bg, чтобы отправить его в фоновый режим, затем используйте disown с флагом -h.
Не забудьте указать свою работу в фоновом режиме, иначе она будет убита, когда вы выйдете из системы.
Это мило! Так много раз я хотел это сделать. Можете ли вы потом перенаправить выходы?
Лучше получить PID от jobs -l (или -p)
Эх - однажды я написал программу на языке C, по сути, для fork() и exec() его аргументов, по сути, для демонизатора. Я могу бомбить оболочку и запускать что-нибудь за один раз bgexec google-chrome && exit.
Разве это не та же функциональность, что и screen?
Быстрое и грязное исправление опечаток (особенно полезно для длинных команд при медленных соединениях, когда использование истории команд и ее прокрутка было бы ужасно):
$ cat /proc/cupinfo
cat: /proc/cupinfo: No such file or directory
$ ^cup^cpu
Также попробуйте !:s/old/new, который один раз заменяет старое на новое в предыдущей команде.
Если вы хотите заменить много вхождений, вы можете выполнить глобальную замену с помощью !:gs/old/new.
Вы можете использовать команды gs и s с любым историческим событием, например
!-2:s/old/new
Заменить old на new (один раз) во второй предпоследней команде.
есть ли способ узнать больше об этой или подобных функциях? поиск в Google для ^ foo ^ bar не так хорош :)
Обозначения событий и модификаторы в man bash. Попробуйте !:s/old/new, который один раз заменяет старое на новое в предыдущей команде. Если вы хотите заменить много вхождений, вы можете выполнить глобальную замену с помощью !:gs/old/new. Это может быть объединено с сообщением Джеймса (stackoverflow.com/questions/211378/hidden-features-of-bash/…), например: !$:s/old/new (заменяет старое на новое в последнем аргументе предыдущей команды), !-2:0:gs/a/s !-2* (заменяет каждое вхождение a на s в имени предпоследней команды и добавляет все аргументы предпоследняя команда). Удачи!
Вот один из моих любимых. Это устанавливает автоматическое завершение табуляции без учета регистра. Это действительно здорово для быстрого ввода путей к каталогам, особенно на Mac, где файловая система по умолчанию не чувствительна к регистру. Я положил это на .inputrc в своей домашней папке.
set completion-ignore-case on
Я не знал об этом, спасибо. Это было в моем ~ / .inputrc, уже закомментированном. Я включил это и показал все, если двусмысленно.
Выполнение команды перед отображением командной строки bash
Задайте команду в переменной env «PROMPT_COMMAND», и она будет запускаться автоматически перед каждым запросом. Пример:
[lsc@home]$ export PROMPT_COMMAND = "date"
Fri Jun 5 15:19:18 BST 2009
[lsc@home]$ ls
file_a file_b file_c
Fri Jun 5 15:19:19 BST 2009
[lsc@home]$ ls
Для следующих апрельских дураков добавьте «export PROMPT_COMMAND = cd» в чей-нибудь .bashrc, затем сядьте и наблюдайте, как разворачивается неразбериха.
SECONDS=0; sleep 5 ; echo "that took approximately $SECONDS seconds"
SECONDS
Each time this parameter is referenced, the number of seconds since shell invocation is returned. If a value is assigned to SECONDS, the value returned upon subsequent references is the number of seconds since the assignment plus the value assigned. If SECONDS is unset, it loses its special properties, even if it is subsequently reset.
Использование встроенной команды bash 'let' для базовой арифметики
A=10
let B = "A * 10 + 1" # B=101
let B = "B / 8" # B=12, let does not do floating point
let B = "(RANDOM % 6) + 1" # B is now a random number between 1 and 6
Чтобы выполнить вычисления с плавающей запятой, вы можете использовать команду «bc» (не являющуюся частью bash).
FP=`echo "scale=4; 10 / 3" | bc` # FP = "3.3333"
Также есть $(( )) для арифметического расширения и (( )) для тестов.
Эти объекты - еще одна из моих любимых.
export HISTCONTROL=erasedups
export HISTSIZE=1000
Первый гарантирует, что bash не регистрирует команды более одного раза, что действительно улучшит полезность history. Другой увеличивает размер истории до 1000 со значения по умолчанию 100. Я фактически установил это значение на 10000 на своих машинах.
CtrlxCtrle
Это загрузит текущую команду в редактор, определенный в переменной VISUAL. Это действительно полезно для длинных команд, подобных некоторым из перечисленных здесь.
Чтобы использовать vi в качестве редактора:
export VISUAL=vi
set -o vi, затем Esc для команды переходит во встроенное редактирование, простая 'v' переносит команду в полноценный редактор vi.Легко перемещаться между несколькими каталогами
Не скрытая функция, но гораздо более гибкая, чем pushd, которая требует навигации по стеку.
a() { alias $1=cd\ $PWD; }
Где-нибудь cd и типа a 1. Позже, просто набрав 1, вы вернетесь в этот каталог.
Мое любимое:
sudo !!
Повторите предыдущую команду с помощью sudo.
Это частный случай stackoverflow.com/questions/211378/hidden-features-of-bash/…
Это почти как сказать СДЕЛАЙ ЭТО!!
Я часто использую! $ Для обозначения последнего слова последней команды:
$ less foobar.txt
...
# I dont want that file any more
$ rm !$
Вы также можете сделать Alt + . для того же
Это зависит от того, какой у вас режим редактирования строки. В режиме vi (установите -o vi) Alt + . не работает.
man:Ctrl + a и Ctrl + e перемещают курсор в начало и конец текущей строки соответственно.
Ctrl + t и Alt + t заменяют символ и слово перед курсором на текущий, затем перемещают курсор вперед.
Alt + u и Alt + l преобразуют текущее слово (от курсора до конца) в верхний и нижний регистр.
Намекать: Нажмите Alt + –, а затем любую из этих команд, чтобы преобразовать начало текущего слова.
man:При просмотре страниц man используйте / для поиска текста на страницах. Используйте n для перехода к следующему совпадению или N для предыдущего совпадения.
Ускорьте поиск конкретной команды или подраздела на страницах man, воспользовавшись их форматированием:
o Вместо того, чтобы набирать /history expansion, чтобы найти этот раздел, попробуйте /^history, используя курсор (^), чтобы найти только строки, которые начинать с «историей».
o Попробуйте / read с несколькими пробелами в начале, чтобы найти эту встроенную команду. Встроенные модули всегда имеют отступ на страницах man.
Ctrl + r начинает «обратный инкрементный поиск» по истории ваших команд. По мере того, как вы продолжаете вводить, он извлекает самую последнюю команду, содержащую весь введенный вами текст.
Tab завершает набранное вами слово, если оно недвусмысленно.
TabTab перечисляет все окончания введенного вами слова.
Alt + *вставки все возможные варианты завершения, что особенно полезно, например, если вы только что ввели потенциально деструктивную команду с подстановочными знаками:
rm -r source/d*.cAlt + *rm -r source/delete_me.c source/do_not_delete_me.c
Ctrl + Alt + e выполняет псевдоним, историю и расширение оболочки в текущей строке. Другими словами, текущая строка отображается повторно, поскольку она будет обработана оболочкой:
ls $HOME/tmpCtrlAlt + els -N --color=tty -T 0 /home/cramey
+1 для alt + * (или alt-shift-8), что позволяет увидеть ошибку, которую вы собираетесь совершить
Я включил функцию "показать все, если двусмысленно", чтобы не нажимать Tab дважды.
Как уже упоминалось, Ctrl-r отлично подходит для возврата к истории команд. Но что, если вы хотите двигаться вперед после того, как сделали на один или несколько шагов слишком много? Вот где пригодится Ctrl-s. Однако обычно он отображается на XOFF (поток данных прерывания). Поскольку это уже не очень полезно, потому что мы не используем медленные последовательные терминалы, вы можете отключить это сопоставление с помощью:
stty -ixon
в вашем файле ~/.bashrc.
Это также делает доступным Ctrl-q, который обычно является дубликатом Ctrl-v (цитируемая вставка, которая позволяет вставлять буквальный управляющий символ). У меня есть Ctrl-q, сопоставленный с завершением меню, которое проходит через завершение при повторном нажатии. Я предпочитаю оставлять Tab в обычном состоянии.
Вы можете настроить Ctrl-q на завершение меню, добавив эту строку в свой файл ~/.inputrc:
"\C-q": menu-complete
Bash имеет косвенное обращение к переменным:
$ foo=bar
$ baz=foo
$ echo ${!baz}
bar
У меня есть псевдоним r='fc-s', и я считаю его очень полезным в некоторых ограниченных случаях. Чтобы запустить последнюю команду, просто введите r и нажмите Enter, и все. Конечно, это само по себе не очень полезно, потому что стрелка вверх делает то же самое. Но вы можете использовать r для выполнения предыдущей команды с заменами. Допустим, ваша последняя команда была длинной командой, компилирующей какой-то файл:
$ gcc -c <file_name>.c <lots of options> -o <file_name>.o
Теперь вы хотите скомпилировать другой файл с теми же параметрами и получить соответствующий файл .o:
$ r <file_name>=<new_file>
сделаю это. Вам не нужно использовать стрелку вверх, переходите в нужные места и затем заменяйте их вручную. Это можно повторить несколько раз, поэтому вы можете сделать следующее:
$ r <new_file>=<other_file>
Конечно, для этого у вас есть make-файлы, но я надеюсь, что показал, что псевдоним полезен.
Мне нечасто нужно было использовать этот псевдоним, но были времена, когда я был рад, что у меня есть этот псевдоним!
export TMOUT=$((15*60))
Завершить bash через 15 минут простоя, установите значение 0, чтобы отключить. Обычно я помещаю его в ~ / .bashrc в моих учетных записях root. Это удобно при администрировании ваших ящиков, и вы можете забыть выйти из системы, прежде чем уходить от терминала.
Не совсем особенность, а скорее направление: я нашел много «скрытых возможностей», секретов и различных полезных функций bash в commandlinefu.com. Многие из самых популярных ответов на эти ответы, я узнал их на этом сайте :)
set -o vi, чтобы иметь возможность редактировать историю команд в стиле vi, а также текущую набранную команду.
C-S--Control Shift Minus Отменяет действия ввода.
Любая операция удаления C-w (удаление предыдущего слова), C-k (удаление до конца строки), C-u (удаление до начала строки) и т. д. Копирует удаленный текст в список уничтожений, вы можете вставить последнее уничтожение с помощью: C-y и перебрать (и вставить) кольцо удаленных элементов с помощью Alt-y
Вы можете игнорировать определенные файлы при заполнении вкладки, установив переменную FIGNORE.
Например, если у вас есть репозиторий Subverion и вы хотите более легко перемещаться, выполните
export FIGNORE = ".svn"
теперь вы можете cd, не будучи заблокированным каталогами .svn.
Еще один маленький: Alt + #
комментирует текущую строку и перемещает ее в буфер истории.
Поэтому, когда вы собираете командную строку, и вам нужно ввести временную команду, например, Чтобы найти файл, вы просто нажимаете alt + #, вводите другую команду, поднимаетесь в истории, раскомментируете и продолжаете.
Здесь струны (<<<). Руководство Bash дает это описание:
The word is expanded and supplied to the command on its standard input.
Пример:
$ cat<<<"$(( 10*3+1 )) nice isn't it?"
31 nice isn't it?
Подстановка процесса с помощью <(cmd ...) или> (cmd ...)
В каждой форме cmd выполняется со своим входом или выходом, подключенным к FIFO, и путь к этому FIFO подставляется в командную строку:
$ echo A file to read: <(cat), a file to write to: >(cat)
A file to read: /dev/fd/63, a file to write to: /dev/fd/62
Например, чтобы сравнить два сайта без сохранения промежуточных файлов:
$ diff <(curl -s http://tldp.org/LDP/abs/html/) <(curl -s http://www.redhat.com/mirrors/LDP/LDP/abs/html/)
Если у вас есть команда, которая принимает имя файла в качестве входных данных, но не принимает '-' в значении stdout, вы можете обмануть ее:
$ do_thingee --log -
error: can't open log file: '-'
$ do_thingee --log >(cat)
do_thingee v0.2
initializing things
processing 4 things
done
Специальные имена файлов сокетов: / dev / tcp / HOST / PORT и / dev / udp / HOST / PORT
Чтение с дневного сервера (порт 13):
$ cat < /dev/tcp/utcnist.colorado.edu/13
55786 11-08-13 03:34:21 50 0 0 172.3 UTC(NIST) *
Это может быть весьма полезно в сочетании с tcpserver.
Более сложный пример из http://thesmithfam.org/blog/2006/05/23/bash-socket-programming-with-devtcp-2/, если у вас нет доступа к wget или curl:
$ exec 3<>/dev/tcp/www.google.com/80 # hook up to file desc 3
$ echo -e "GET / HTTP/1.1\n\n" >&3 # send the HTTP request
$ cat <&3 # read the HTTP response
Расширение скобы
Стандартное расширение с {x, y, z}:
$ echo foo{bar,baz,blam}
foobar foobaz fooblam
$ cp program.py{,.bak} # very useful with cp and mv
Расширение последовательности с помощью {x..y}:
$ echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
$ echo {a..f}{0..3}
a0 a1 a2 a3 b0 b1 b2 b3 c0 c1 c2 c3 d0 d1 d2 d3 e0 e1 e2 e3 f0 f1 f2 f3
Быстрый поиск по истории
Следующее дает tcsh-подобный поиск по истории, который удобен и проще.
Добавьте следующие строки в ~/.inputrc или /etc/inputrc.
$ cat ~/.inputrc
"\e[A": history-search-backward
"\e[B": history-search-forward
Вы можете использовать менее случайную комбинацию клавиш, например Esc + p. В этом случае используйте
"\ep": history-search-backward
"\en": history-search-forward
Затем просто введите первые несколько букв и нажмите клавишу со стрелкой вверх. Он покажет самую последнюю команду, начинающуюся с заданных букв.
бывший:
типа grep, UpArrow.
Будет показано что-то вроде grep -ri myText .
Дополнительные сведения о комбинациях клавиш в Bash в http://linuxconfig.net/manual-howto/key-combinations-in-bash.html
Подтяжки вместо do и done в петле for
Тело цикла For обычно находится в do...done (просто пример):
for f in *;
do
ls "$f";
done
Но мы можем использовать стиль C, используя фигурные скобки:
for f in *; {
ls "$f";
}
Думаю, он выглядит лучше, чем do...done, и я предпочитаю этот. Я еще не нашел этого ни в одной документации Bash, так что это действительно скрытая функция.
Это не функция Bash, а внешняя программа: да, '[[' - это отдельная программа.