Как написать пользовательский скрипт

Время на прочтение
7 мин

Количество просмотров 278K

Доброго времени суток всем желающим приобщиться к миру пользовательских скриптов (они же userscript, userJS, юзерскрипты).

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

Внимание: предполагается минимальное знание javascript.
На практике доказано: юзерскрипты может писать человек, не знакомый с программированием, но обладающий усидчивостью и желанием изучить javascript!
О том, что такое javascript и как с ним обращаться, можно узнать на javascript.ru.

Что такое юзерскрипты?

Кратко: юзерскрипт — это программа, написанная на языке JavaScript, хранящаяся на компьютере пользователя и подключаемая браузером на определенных страницах. Юзерскрипт представляет собой файл с расширением .user.js (именно по расширению браузеры понимают, что файл является юзерскриптом), содержащий метаданные и непосредственно javascript-код.

При подключении к странице юзерскрипт выполняется так же, как и обычные javascript-сценарии.
У юзерскрипта есть доступ к DOM-дереву страницы, в контексте которой он выполняется.
В современных браузерах у юзерскрипта есть доступ к localStorage и прочим HTML5 API.

Юзерскрипты поддерживаются всеми основными современными браузерами (и даже кое-как поддерживаются IE7 и выше).

Самый известный портал юзерскриптов — userscripts.org. Тут можно найти хранилище скриптов, инструменты управления своими скриптами на портале и, что не маловажно, отзывчивый форум (всё на английском).

Немного общей теории

Самыми распространенными являются скрипты под расширение GreaseMonkey для браузера Firefox.
Подробную информацию по GreaseMonkey и написанию юзерскриптов под GreaseMonkey можно узнать на http://wiki.greasespot.net.
Так сложилось исторически, что данный браузер был (и остаётся по сей день) первым, в котором поддержка юзерскриптов была выполнена на высоком уровне.

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

криворукости

том, что во многих скриптах используется GM API — набор javascript-функций, специфичных для GreaseMonkey.

Однако, проще всего писать юзерскрипты под браузер Google Chrome.
На это есть ряд причин:

  1. Простым скриптам не нужна поддержка GM API (библиотека, доступная в GreaseMonkey)
  2. Google Chrome, в отличие от Firefox+GreaseMonkey, имеет отличнейший дебаггер.
  3. Сообщения об ошибках юзерскрипта в Firefox ужасны! Если вы не обладаете даром телепатиитвердыми знаниями GreaseMonkey и javascript, написание юзерскрипта может превратится в муки!
  4. Google Chrome не требует расширений для поддержки юзерскриптов. Интерфейс для удаления/отключения юзерскриптов доступен «из коробки».

Очевидные минусы Google Chrome:

  1. Нет доступа к «родному» window.
  2. Не поддерживается директива @ include метаданных. Директива @ match глючит, можно сказать, что она тоже не поддерживается.

Особенности юзерскриптов

Код юзерскриптов может посмотреть любой желающий, вооруженный блокнотом.
Базовые знания javascript позволяют отсечь угрозу установки шпионских и вредоносных скриптов простым анализом кода скрипта (придётся задействовать мозг).

Важно:Если вы не доверяете автору скрипта, главное удостовериться, что скрипт не отсылает пользовательские данные (куки, вводимый текст) на сторонние сервисы!

Все юзерскрипты запускаются после того, как загрузились все основные элементы страницы, но ещё не загрузились картинки. Можно сказать, что юзерскрипты грузятся по событию DOMContentLoaded.
В любом случае, проверки на window.onload не нужны.

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

и шлюх

(юзерскрипты для социальных сетей).
Бывают и продвинутые юзерскрипты, которые представляют собой самостоятельные программы (аукционные и игровые боты, плагины-помощники и т.д).

Анатомия юзерскриптов

Юзерскрипт — это текстовый файл с расширением user.js. В начале файла располагается блок метаданных — описание самого скрипта. После блока метаданных следует javascript-код, который и будет исполняться браузером.

Рассмотрим тестовый скрипт, который показывает alert с текстом на определенной странице.

// ==UserScript==
// @name myUserJS
// @description Мой самый первый юзерскрипт 
// @author Vasya Pupkin
// @license MIT
// @version 1.0
// @include http://userscripts.org/*
// ==/UserScript==
// [1] Оборачиваем скрипт в замыкание, для кроссбраузерности (opera, ie)
(function (window, undefined) {  // [2] нормализуем window
    var w;
    if (typeof unsafeWindow != undefined) {
        w = unsafeWindow
    } else {
        w = window;
    }
    // В юзерскрипты можно вставлять практически любые javascript-библиотеки.
    // Код библиотеки копируется прямо в юзерскрипт.
    // При подключении библиотеки нужно передать w в качестве параметра окна window
    // Пример: подключение jquery.min.js
    // (function(a,b){function ci(a) ... a.jQuery=a.$=d})(w);

    // [3] не запускаем скрипт во фреймах
    // без этого условия скрипт будет запускаться несколько раз на странице с фреймами
    if (w.self != w.top) {
        return;
    }
    // [4] дополнительная проверка наряду с @include
    if (/http://userscripts.org/.test(w.location.href)) {
        //Ниже идёт непосредственно код скрипта
        alert("Userscripts приветствует вас навязчивым окном.");
    }
})(window);

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

В самом начале располагается блок метаданных (в виде комментария).

// ==UserScript==
// ...
// ==/UserScript==

Этот блок состоит из директив описания юзерскрипта. Ниже в таблице представлены основные директивы и их назначение.

Важно:Все директивы, как и сам блок метаданных, могут отсутствовать.

Директива Назначение
@ name Название юзерскрипта.
Это название будет отображаться в интерфейсе управления
юзерскриптами. Если директива отсутствует, то название
юзерскрипта будет таким же, как и название файла.
@ description Описание юзерскрипта.
Это описание будет отображаться в интерфейсе управления
юзерскриптами.
@ namespace Пространство имён.
Определяет уникальность набора скриптов.
Сюда можно вписать имя домена, принадлежащего вам. Или любую другую строку.
Считайте, что это второе название скрипта. Обязательная директива для Trixie!
@ author Имя автора.
@ license Название лицензии, по которой распространяется юзерскрипт.
@ version Номер версии юзерскрипта.
К сожалению, механизма автообновления нету ни в одном браузере,
поэтому номер версии — это просто цифры, которые отображаются в интерфейсе.
@ include Директива описания url страницы,
на которой нужно запускать юзерскрипт.
Поддерживает вайлдкард *(применимо в GreaseMoneky, Opera, IE).
Для каждого отдельного url нужно использовать отдельную директиву @ include.
@ exclude Директива описания url страницы,
на которой не нужно запускать юзерскрипт.
Поддерживает вайлдкард *(применимо в GreaseMonkey, Opera, IE).
Для каждого отдельного url нужно использовать отдельную директиву @ exclude.
@ match Аналогично @ include, но с более жесткими ограничениями
(применимо в GreaseMonkey старше 0.9.8, Google Chrome).
Подробнее об ограничениях и формате директивы можно
прочитать на этой странице.
Для каждого отдельного url нужно использовать отдельную директиву @ match.

Важно: Как показала практика, полагаться на директиву @ match в юзерскриптах не стоит.
Google Chrome периодически отказывается учитывать @ match
и запускает юзерскрипты на всех страницах.
Для предотвращения такой ситуации в юзерскрипты,
которые будут запускаться не только в Firefox,
нужно добавлять код проверки адреса страницы (см. ссылку [4] в коде юзерскрипта).

Важно: При отсутствии директив @ include или @ match, юзерскрипты будут запускаться на всех страницах.

В нашем юзерскрипте использован ряд хитростей:

  1. Для того, чтобы юзерскрипты имели одинаковое поведение и не загрязняли глобальную область видимости, код оборачивается в замыкание (см. [1] в коде скрипта).
  2. Для правильного подключения библиотек внутри юзерскрипта и для обхода некоторых хитрых особеннойстей GreaseMonkey, необходимо «нормализовать» ссылку на глобальную область видимости window (см. [2] в коде скрипта).
  3. Для того, чтобы юзерскрипт не запускался несколько раз на одной и той же странице, необходимо останавливать работу при запуске юзерскрипта во фреймах (см. [3] в коде скрипта).
  4. Для того, чтобы юзерскрипт запускался только на нужных нам страницах, необходимо явно проверять url страницы (см. [4] в коде скрипта).
  5. Благодаря такой структуре, юзерскрипт может быть относительно просто преобразован в букмарклет.

Результат

Наш юзерскрипт готов к использованию!
Нет, серьёзно, вы можете скопировать код юзерскрипта в файл, назвать его my.user.js, и закинуть полученный файл в браузер (используйте Chrome или Firefox с установленным GreaseMonkey).

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

Остаётся вопрос: как «раздать» наш скрипт пользователям (ведь мы писали скрипт не только для себя)?
Варианты:

  • Зарегестрироваться на портале userscripts.org и загружать скрипты туда.
  • Завести репозиторий на code.google.com или github.com.
  • Создать свой простой сервис/сайт/страничку.
    Важно:Если хотите, чтобы у пользователей GreaseMonkey автоматически открывался диалог установки юзерскрипта, отдавайте файл прямиком с файловой системы (url файла должен заканчиваться на .user.js). В противном случае пользователь увидит исходный код скрипта и панель с кнопкой «установить». Эта кнопка не работает!

Рецепт для непрограммистов (похожими методами пишется ~70% скриптов):

  1. Придумываем, что будет делать наш юзерскрипт (перекрашивать ссылки, например)
  2. Берём шаблон из статьи
  3. Сохраняем в файл my.user.js
  4. Удаляем строку с alert(…).
  5. Идём на форум (userscripts.org или любой форум по javascript).
  6. Спамим, флудим и достаём людей вопросами «как перекрашивать ссылки», «дайте код» и т.д.
  7. Изменяем метаданные и проверку url страницы на нужные нам.
  8. Вставляем полученный на форуме код в юзерскрипт.
  9. Сохраняем файл.
  10. PROFIT!!1!

Полезные ссылки:

  • Userscripts.org
  • wiki.greasespot.net
  • Userscript -> Firefox Extension Compiler
  • Writing userscripts
  • Правила директивы @ match

Список статей:

  1. » Учимся писать userscript’ы
  2. Userscripts. Углубляемся.
  3. Userscripts. Упаковываем юзерскрипт для Chrome
  4. Usersctripts. Кроссдоменные запросы

P.S. Хотелось бы увидеть блог Userscripts на хабре. Ибо не одним GreaseMonkey едины.

Applying JavaScript: User Scripts

by Thomas Noe

NgPJAVqUOAt1M4JQzWvriuFYKUNwTgUcFuFj

Art credit

Writing a Userscript is a fun way to use your JavaScript skills. It takes you out of the editor into the browser with real time feedback and validation.

What is a user script?

Userscripts (a.k.a User Scripts, User scripts, or .user.js) are open-source licensed add-ons for web browsers that change web pages as they are loaded. They give users the power to make websites do what they want them to, rather than what was originally intended.

User scripts are written in JavaScript and allow you to tweak the look and feel of a webpage on your browser. The scripts only effect your browser, not the actual webpage.

A quick warning

You should be aware of privacy issues when using userscripts, and should not install them from sources you do not trust. Userscripts can carry out actions on your behalf and can potentially access any information on a website you have access to, or that you enter into a website. They are often permitted to carry out functions that scripts on normal websites cannot, such as storing information on your computer and sharing it between website. Badly written userscripts could potentially also be exploited by malicious websites.

explanations taken from https://github.com/OpenUserJs/OpenUserJS.org/wiki/Userscript-Beginners-HOWTO

Why user scripts?

Free Code Camp has a lot of great real world projects that will enrich your skill set and portfolio. I personally like using the skills I have learned in JavaScript, jQuery, and CSS to modify my day to day browsing.

Some User Scripts have been extremely popular and were made into browser extensions. An example of one would be the Reddit Enhancement Suite found at http://redditenhancementsuite.com/.

You too could use your user script as a base of a browser extension!

Getting started

User scripts are run from browser extensions themselves. Grease Monkey (FireFox) was the pioneer add on to allow people to customize their browsing experience. Install the appropriate plug in for your browser.

For FireFox: Grease Monkey

Greasemonkey
The Development Channel lets you test an experimental new version of this add-on before it’s released to the general…addons.mozilla.org

For Chrome: Tamper Monkey

Tampermonkey
The most popular userscript manager for Blink-based browserschrome.google.com

For this tutorial I will be using Chrome with Tamper Monkey.

There shouldn’t be any significant differences with the process after installing either Grease Monkey or Tamper Monkey.

Just in case, here is a quick link to installing Grease Monkey (as well as making a few things with it.)

Greasemonkey Tutorial for Beginners
In Greasemonkey tutorial, I have covered how to write Greasemonkey user scripts. After this tutorial,you will be able…hayageek.com

the project

We are going to be making a slight change to the home page on Hacker News http://news.ycombinator.com.

6ICv092GpRSQFSCbogHBMCj3IBqWVqV0d7il

HackerNews homepage

We will be using jQuery to make alternating links background colors slightly different to improve readability.

start a new script

Click on the Tamper Monkey icon in the top right and select ‘Add a new script’ from the dialog box.

You should be brought to a new tab that looks like this

MnG62eij5rouor9HWsShflip5d1uJAH7bGGf

new script page

Fill in the information

After starting a new script the first thing we want to do is fill in the script information at the top. Go ahead and fill in the following attributes how ever you want

  • name
  • description
  • author

I will show you what mine looks like as well.

Add jQuery

right before the line

// ==/UserScript==

add a line with the text of

// @require http://code.jquery.com/jquery-latest.js

Think of this as importing/requiring jQuery for a JS project.

here is mine

9BlQRN0ORWp6K2ak0A-f6UD71dWwN4bTrDYp

script info filled out

Hello script.js!

Let’s see if it our script loads on http://news.ycombinator.com and jQuery is good to go.

After the // your code here line add the following code

$(document).ready(function() {  alert('WINNING');});

and enter Ctrl + s or click on the save button on the left

You may be brought to the following page. If not, click on the Installed userscripts tab.

RwzBGDralHUJYCaJUxb6ZFE1J-fo-IKkp1RT

installed userscripts page

Awesome! Out script is loaded into Tamper Monkey. The green dot on the left means that the script is turned on. You can even see the Hacker News logo in the screenshot.

execute the script

Visit Hacker News in your browser and if you’ve been following along and everything went well, you should see

kjO1MKNyMj0C1jza9KjXNqozJbJVwQJNjAJ2

working alert dialog

Fire up the debugger

It’s time to find the post elements we want to modify. Enter Ctrl + Shift + i to bring up the browser debugger.

Now we want to select an element to take a closer look. Clicking on the blue square with the mouse in it at the top left of the debugger will open the element selector. You can also use the key command Ctrl + Shift + c.

K57nqIwcj2tQz8CqY31YuHLVdClePaxYqHFX

element selector

As you can see I found an element called td.title. After clicking on it the element is highlighted in the elements tab of the debugger (also shown above.)

Highlighting the element above our title called

<tr class="athing">

selects this in the browser

3jTJbC0gL7Irgh-qfpzNbW5hksEdjfTKC6O5

BINGO

Bingo. It looks like we found the element we want. Hacker News has a clean HTML layout so it wasn’t too difficult to find our target element.

If you remember your jQuery, all you have to do to find all of the post elements is use the selector

$('.athing')

do something to our post element

Now that we have a way to select our element with jQuery we can alter our element. Let’s change the background color of the posts using the following code. Change the $(document).ready() code to this

$(document).ready(function() {  $('.athing').css('background-color', '#DDD');});

note: #DDD is shorthand for #DDDDDD;

let’s look at the resulting page. Remember to save your userscript then refresh the HackerNews page. You may have to close your debugger to view the whole page.

vkeMepNz7Ixs6vh5lBbQqqBrtqwSaqnKK4TG

altered Hacker News front page

Are we done yet? Not quite. We have changed all of our post elements instead of alternating. It may look like the zebra effect we wanted but that’s only because the score/subinfo element isn’t effected. If you feel inclined to alter that element as well please do and feel free to post your method in the comments. It’s outside of the scope of this guide.

Oh no?! What do we do… I don’t want to write any loops!

jQuery to the rescue

Have no fear, fellow Campers. jQuery has come to the rescue yet again.

jQuery provides special selectors just for an occasion like this.

Now introducing :odd

:odd Selector
Description: Selects odd elements, zero-indexed. See also even. In particular, note that the 0-based indexing means…api.jquery.com

all we have to do is add :odd to the end of our selector so that the line looks like this. note: I have also changed the color to #EEE; to blend in better.

    $(‘.athing:odd’).css(‘background-color’, ‘#EEE’);

Save your script and refresh HackerNews and you should see this final product

U2VcB-db2IvtuKrjzSfEfcKxU3jYxARMG1rV

final product

Wraping up

There you have it. Now you have another creative outlet to unleash your budding coding wizardry on! User Scripts can be used to tweak the functionality or look of a site, to add a feature you’ve always wanted, plus much more.

Homework

Write your own User Script to add something to a website you use often. Whether it be styling or a button that can toggle the visibility of certain elements, it’s all up to you. Provide your product in the comments here!

Go forth and conquer Campers!

More reading

Tampermonkey
Tampermonkey is a free browser extension and the most popular userscript manager for Blink-based Browsers like Chrome…tampermonkey.netGreaseSpot Wiki
GreaseSpot is community documentation for user scripting with Greasemonkey.wiki.greasespot.netGreasy Fork — safe and useful user scripts
User scripts put you in control of your browsing experience. Once installed, they automatically make the sites you…greasyfork.orgGetting Started: Building a Chrome Extension
Extensions allow you to add functionality to Chrome without diving deeply into native code. You can create new…developer.chrome.comHow to develop a Firefox extension
This blog post is very outdated. If you want a more recent guide to extension development, please read the new How to…blog.mozilla.org


Learn to code for free. freeCodeCamp’s open source curriculum has helped more than 40,000 people get jobs as developers. Get started

Applying JavaScript: User Scripts

by Thomas Noe

NgPJAVqUOAt1M4JQzWvriuFYKUNwTgUcFuFj

Art credit

Writing a Userscript is a fun way to use your JavaScript skills. It takes you out of the editor into the browser with real time feedback and validation.

What is a user script?

Userscripts (a.k.a User Scripts, User scripts, or .user.js) are open-source licensed add-ons for web browsers that change web pages as they are loaded. They give users the power to make websites do what they want them to, rather than what was originally intended.

User scripts are written in JavaScript and allow you to tweak the look and feel of a webpage on your browser. The scripts only effect your browser, not the actual webpage.

A quick warning

You should be aware of privacy issues when using userscripts, and should not install them from sources you do not trust. Userscripts can carry out actions on your behalf and can potentially access any information on a website you have access to, or that you enter into a website. They are often permitted to carry out functions that scripts on normal websites cannot, such as storing information on your computer and sharing it between website. Badly written userscripts could potentially also be exploited by malicious websites.

explanations taken from https://github.com/OpenUserJs/OpenUserJS.org/wiki/Userscript-Beginners-HOWTO

Why user scripts?

Free Code Camp has a lot of great real world projects that will enrich your skill set and portfolio. I personally like using the skills I have learned in JavaScript, jQuery, and CSS to modify my day to day browsing.

Some User Scripts have been extremely popular and were made into browser extensions. An example of one would be the Reddit Enhancement Suite found at http://redditenhancementsuite.com/.

You too could use your user script as a base of a browser extension!

Getting started

User scripts are run from browser extensions themselves. Grease Monkey (FireFox) was the pioneer add on to allow people to customize their browsing experience. Install the appropriate plug in for your browser.

For FireFox: Grease Monkey

Greasemonkey
The Development Channel lets you test an experimental new version of this add-on before it’s released to the general…addons.mozilla.org

For Chrome: Tamper Monkey

Tampermonkey
The most popular userscript manager for Blink-based browserschrome.google.com

For this tutorial I will be using Chrome with Tamper Monkey.

There shouldn’t be any significant differences with the process after installing either Grease Monkey or Tamper Monkey.

Just in case, here is a quick link to installing Grease Monkey (as well as making a few things with it.)

Greasemonkey Tutorial for Beginners
In Greasemonkey tutorial, I have covered how to write Greasemonkey user scripts. After this tutorial,you will be able…hayageek.com

the project

We are going to be making a slight change to the home page on Hacker News http://news.ycombinator.com.

6ICv092GpRSQFSCbogHBMCj3IBqWVqV0d7il

HackerNews homepage

We will be using jQuery to make alternating links background colors slightly different to improve readability.

start a new script

Click on the Tamper Monkey icon in the top right and select ‘Add a new script’ from the dialog box.

You should be brought to a new tab that looks like this

MnG62eij5rouor9HWsShflip5d1uJAH7bGGf

new script page

Fill in the information

After starting a new script the first thing we want to do is fill in the script information at the top. Go ahead and fill in the following attributes how ever you want

  • name
  • description
  • author

I will show you what mine looks like as well.

Add jQuery

right before the line

// ==/UserScript==

add a line with the text of

// @require http://code.jquery.com/jquery-latest.js

Think of this as importing/requiring jQuery for a JS project.

here is mine

9BlQRN0ORWp6K2ak0A-f6UD71dWwN4bTrDYp

script info filled out

Hello script.js!

Let’s see if it our script loads on http://news.ycombinator.com and jQuery is good to go.

After the // your code here line add the following code

$(document).ready(function() {  alert('WINNING');});

and enter Ctrl + s or click on the save button on the left

You may be brought to the following page. If not, click on the Installed userscripts tab.

RwzBGDralHUJYCaJUxb6ZFE1J-fo-IKkp1RT

installed userscripts page

Awesome! Out script is loaded into Tamper Monkey. The green dot on the left means that the script is turned on. You can even see the Hacker News logo in the screenshot.

execute the script

Visit Hacker News in your browser and if you’ve been following along and everything went well, you should see

kjO1MKNyMj0C1jza9KjXNqozJbJVwQJNjAJ2

working alert dialog

Fire up the debugger

It’s time to find the post elements we want to modify. Enter Ctrl + Shift + i to bring up the browser debugger.

Now we want to select an element to take a closer look. Clicking on the blue square with the mouse in it at the top left of the debugger will open the element selector. You can also use the key command Ctrl + Shift + c.

K57nqIwcj2tQz8CqY31YuHLVdClePaxYqHFX

element selector

As you can see I found an element called td.title. After clicking on it the element is highlighted in the elements tab of the debugger (also shown above.)

Highlighting the element above our title called

<tr class="athing">

selects this in the browser

3jTJbC0gL7Irgh-qfpzNbW5hksEdjfTKC6O5

BINGO

Bingo. It looks like we found the element we want. Hacker News has a clean HTML layout so it wasn’t too difficult to find our target element.

If you remember your jQuery, all you have to do to find all of the post elements is use the selector

$('.athing')

do something to our post element

Now that we have a way to select our element with jQuery we can alter our element. Let’s change the background color of the posts using the following code. Change the $(document).ready() code to this

$(document).ready(function() {  $('.athing').css('background-color', '#DDD');});

note: #DDD is shorthand for #DDDDDD;

let’s look at the resulting page. Remember to save your userscript then refresh the HackerNews page. You may have to close your debugger to view the whole page.

vkeMepNz7Ixs6vh5lBbQqqBrtqwSaqnKK4TG

altered Hacker News front page

Are we done yet? Not quite. We have changed all of our post elements instead of alternating. It may look like the zebra effect we wanted but that’s only because the score/subinfo element isn’t effected. If you feel inclined to alter that element as well please do and feel free to post your method in the comments. It’s outside of the scope of this guide.

Oh no?! What do we do… I don’t want to write any loops!

jQuery to the rescue

Have no fear, fellow Campers. jQuery has come to the rescue yet again.

jQuery provides special selectors just for an occasion like this.

Now introducing :odd

:odd Selector
Description: Selects odd elements, zero-indexed. See also even. In particular, note that the 0-based indexing means…api.jquery.com

all we have to do is add :odd to the end of our selector so that the line looks like this. note: I have also changed the color to #EEE; to blend in better.

    $(‘.athing:odd’).css(‘background-color’, ‘#EEE’);

Save your script and refresh HackerNews and you should see this final product

U2VcB-db2IvtuKrjzSfEfcKxU3jYxARMG1rV

final product

Wraping up

There you have it. Now you have another creative outlet to unleash your budding coding wizardry on! User Scripts can be used to tweak the functionality or look of a site, to add a feature you’ve always wanted, plus much more.

Homework

Write your own User Script to add something to a website you use often. Whether it be styling or a button that can toggle the visibility of certain elements, it’s all up to you. Provide your product in the comments here!

Go forth and conquer Campers!

More reading

Tampermonkey
Tampermonkey is a free browser extension and the most popular userscript manager for Blink-based Browsers like Chrome…tampermonkey.netGreaseSpot Wiki
GreaseSpot is community documentation for user scripting with Greasemonkey.wiki.greasespot.netGreasy Fork — safe and useful user scripts
User scripts put you in control of your browsing experience. Once installed, they automatically make the sites you…greasyfork.orgGetting Started: Building a Chrome Extension
Extensions allow you to add functionality to Chrome without diving deeply into native code. You can create new…developer.chrome.comHow to develop a Firefox extension
This blog post is very outdated. If you want a more recent guide to extension development, please read the new How to…blog.mozilla.org


Learn to code for free. freeCodeCamp’s open source curriculum has helped more than 40,000 people get jobs as developers. Get started

Бесплатная книга-сайт на русском, полный гайд
Advanced Bash-Scripting Guide

Введение

BASH — Bourne-Again SHell (что может переводится как «перерожденный шел», или «Снова шел Борна(создатель sh)»), самый популярный командный интерпретатор в юниксоподобных системах, в особенности в GNU/Linux. Ниже приведу ряд встроенных команд, которые мы будем использовать для создания своих скриптов.

break выход из цикла for, while или until
continue выполнение следующей итерации цикла for, while или until
echo вывод аргументов, разделенных пробелами, на стандартное устройство вывода
exit выход из оболочки
export отмечает аргументы как переменные для передачи в дочерние процессы в среде
hash запоминает полные имена путей команд, указанных в качестве аргументов, чтобы не искать их при следующем обращении
kill посылает сигнал завершения процессу
pwd выводит текущий рабочий каталог
read читает строку из ввода оболочки и использует ее для присвоения значений указанным переменным.
return заставляет функцию оболочки выйти с указанным значением
shift перемещает позиционные параметры налево
test вычисляет условное выражение
times выводит имя пользователя и системное время, использованное оболочкой и ее потомками
trap указывает команды, которые должны выполняться при получении оболочкой сигнала
unset вызывает уничтожение переменных оболочки
wait ждет выхода из дочернего процесса и сообщает выходное состояние.

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

Что необходимо знать с самого начала

  1. Любой bash-скрипт должен начинаться со строки:

#!/bin/bash

в этой строке после #! указывается путь к bash-интерпретатору, поэтому если он у вас установлен в другом месте(где, вы можете узнать набрав whereis bash) поменяйте её на ваш путь.

  1. Коментарии начинаются с символа # (кроме первой строки).
  2. В bash переменные не имеют типа(о них речь пойдет ниже)

Переменные и параметры скрипта

Приведу как пример небольшой пример, который мы разберем:

#!/bin/bash #указываем где у нас хранится bash-интерпретатор
#присваиваем переменной parametr1 значение первого параметра скрипта
parametr1=$1
#присваиваем переменной script_name значение имени скрипта
script_name=$0
# команда echo выводит определенную строку, обращение к переменным осуществляется через $имя_переменной.
echo "Вы запустили скрипт с именем $script_name и параметром $parametr1"
# здесь мы видим другие кавычки, разница в том, что в одинарных кавычках не происходит подстановки переменных.
echo 'Вы запустили скрипт с именем $script_name и параметром $parametr1'
#Выход с кодом 0 (удачное завершение работы скрипта)
exit 0

Результат выполнения скрипта:

ite@ite-desktop:~$ ./test.sh qwerty
Вы запустили скрипт с именем ./test.sh и параметром qwerty
Вы запустили скрипт с именем $script_name и параметром $parametr1

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

$DIRSTACK — содержимое вершины стека каталогов
$EDITOR — текстовый редактор по умолчанию
$EUID — Эффективный UID. Если вы использовали программу su для выполнения команд от другого пользователя, то эта переменная содержит UID этого пользователя, в то время как…
$UID — …содержит реальный идентификатор, который устанавливается только при логине.
$FUNCNAME — имя текущей функции в скрипте.
$GROUPS — массив групп к которым принадлежит текущий пользователь
$HOME — домашний каталог пользователя
$HOSTNAME — ваш hostname
$HOSTTYPE — архитектура машины.
$LC_CTYPE — внутренняя переменная, котороя определяет кодировку символов
$OLDPWD — прежний рабочий каталог
$OSTYPE — тип ОС
$PATH — путь поиска программ
$PPID — идентификатор родительского процесса
$SECONDS — время работы скрипта(в сек.)
$# — общее количество параметров переданных скрипту
$* — все аргументы переданыне скрипту(выводятся в строку)
$@ — тоже самое, что и предыдущий, но параметры выводятся в столбик
$! — PID последнего запущенного в фоне процесса
$$ — PID самого скрипта

Условия

Условные операторы, думаю, знакомы практически каждому, кто хоть раз пытался на чем-то писать программы. В bash условия пишутся след. образом (как обычно на примере):

#!/bin/bash
#в переменную source засовываем первый параметр скрипта
source=$1
#в переменную dest засовываем второй параметр скрипта
dest=$2

# в ковычках указываем имена переменных для сравнения. -eq — логическое сравнение обозначающие «равны»
if [[ "$source" -eq "$dest" ]]
# если они действительно равны, то
then
#выводим сообщение об ошибке, т.к. $source и $dest у нас равны
echo "Применик $dest и источник $source один и тот же файл!"
# выходим с ошибкой (1 — код ошибки)
exit 1
# если же они не равны
else
# то выполняем команду cp: копируем источник в приемник
cp $source $dest
echo "Удачное копирование!"
fi #обозначаем окончание условия.

Результат выполнения скрипта:

ite@ite-desktop:~$ ./primer2.sh 1 1
Применик 1 и источник 1 один и тот же файл!

ite@ite-desktop:~$ ./primer2.sh 1 2
Удачное копирование!

Структура if-then-else используется следующим образом:

if <команда или набор команд возвращающих код возврата(0 или 1)>
then
<если выражение после if истино, то выполняется этот блок>
else
<если выражение после if ложно, тот этот>

В качестве команд возвращающих код возврата могут выступать структуры [[ , [ , test, (( )) или любая другая(или несколько) linux-команда.

test — используется для логического сравнения. после выражения, неоьбходима закрывающая скобка «]»
[ — синоним команды test
[[ — расширенная версия «[» (начиная с версии 2.02)(как в примере), внутри которой могут быть использованы || (или), & (и). Долна иметь закрывающуб скобку «]]»
(( )) — математическое сравнение.

для построения многоярусных условий вида:

if ...
then ....
else
if ....
then....
else ....

для краткости и читаемости кода, можно использовать структуру:

if ..
then ...
elif ...
then ...
elif ...

Условия. Множественный выбор

Если необходимо сравнивать какоую-то одну переменную с большим количеством параметров, то целесообразней использовать оператор case.

#!/bin/bash
echo "Выберите редатор для запуска:"
echo "1 Запуск программы nano"
echo "2 Запуск программы vi"
echo "3 Запуск программы emacs"
echo "4 Выход"
#здесь мы читаем в переменную $doing со стандартного ввода
read doing

case $doing in
1)
/usr/bin/nano # если $doing содержит 1, то запустить nano
;;
2)
/usr/bin/vi # если $doing содержит 2, то запустить vi
;;
3)
/usr/bin/emacs # если $doing содержит 3, то запустить emacs
;;
4)
exit 0
;;
*) #если введено с клавиатуры то, что в case не описывается, выполнять следующее:
echo "Введено неправильное действие"

esac #окончание оператора case.

Результат работы:

ite@ite-desktop:~$ ./menu2.sh
Выберите редатор для запуска:
1 Запуск программы nano
2 Запуск программы vi
3 Запуск программы emacs
4 Выход

После выбор цифры и нажатия Enter запуститься тот редактор, который вы выбрали(если конечно все пути указаны правильно, и у вас установлены эти редакторы :) )

Прведу список логических операторв, которые используются для конструкции if-then-else-fi:

-z # строка пуста
-n # строка не пуста
=, (==) # строки равны
!= # строки неравны
-eq # равно
-ne # неравно
-lt,(< ) # меньше
-le,(<=) # меньше или равно
-gt,(>) #больше
-ge,(>=) #больше или равно
! #отрицание логического выражения
-a,(&&) #логическое «И»
-o,(||) # логическое «ИЛИ»

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

Основы BASH. Часть 2

Циклы. Цикл for-in.

Оператор for-in предназначен для поочередного обращения к значениям перечисленным в списке. Каждое значение поочередно в списке присваивается переменной.
Синтаксис следующий:

for переменная in список_значений  
do  
команды  
done  

Рассмотрим небольшой пример:

#!/bin/bash  
for i in 0 1 2 3 4 #переменной $i будем поочередно присваивать значения от 0 до 4 включительно  
do  
echo "Console number is $i" >> /dev/pts/$i #Пишем в файл /dev/pts/$i(файл виртуального терминала) строку "Console number is $i"  
done #цикл окончен  
exit 0  

После выполнения примера в первых 5 виртуальных консолях(терминалах) появится строка с её номером. В переменную $i поочередно подставляются значения из списка и в цикле идет работа со значением этой переменной

Циклы. Цикл while.

Цикл while сложнее цикла for-in и используется для повторения команд, пока какое-то выражение истинно( код возврата = 0).
Синтаксис оператора следующий:

while выражение или команда возвращающая код возврата  
do  
команды  
done  

Пример работы цикла рассмотрим на следующем примере:

#!/bin/bash  
again=yes #присваиваем значение "yes" переменной again  
while [ "$again" = "yes" ] #Будем выполнять цикл, пока $again будет равно "yes"  
do  
echo "Please enter a name:"  
read name  
echo "The name you entered is $name"  
  
echo "Do you wish to continue?"  
read again  
done  
echo "Bye-Bye"  

А теперь результат работы скрипта:

ite@ite-desktop:~$ ./bash2_primer1.sh  
Please enter a name:  
ite  
The name you entered is ite  
Do you wish to continue?  
yes  
Please enter a name:  
mihail  
The name you entered is mihail  
Do you wish to continue?  
no  
Bye-Bye  

Как видим цикл выполняется до тех пор, пока мы не введем что-то отличное от «yes». Между do и done можно описывать любые структуры, операторы и т.п., все они будут выполнятся в цикле.Но следует быть осторожным с этим циклом, если вы запустите на выполнение в нём какую-либо команду, без изменения переменной выражения, вы можете попасть в бесконечный цикл.

Теперь об условии истинности. После while, как и в условном операторе if-then-else можно вставлять любое выражение или команду, которая возвращает код возврата, и цикл будет исполнятся до тех пор, пока код возврата = 0! Оператор [ аналог команды test, которая проверяет истинность условия, которое ей передали.

Рассмотрим еще один пример, я взял его из книги Advanced Bash Scripting. Уж очень он мне понравился :), но я его немного упростил. В этом примере мы познакомимся с еще одним типом циклов UNTIL-DO. Эта практически полный аналог цикла WHILE-DO, только выполняется пока какое-то выражение ложно.
Вот пример:

#!/bin/bash  
echo "Введите числитель: "  
read dividend  
echo "Введите знаменатель: "  
read divisor  
  
dnd=$dividend #мы будем изменять переменные dividend и divisor,  
#сохраним их знания в других переменных, т.к. они нам  
#понадобятся  
dvs=$divisor  
remainder=1  
  
until [ "$remainder" -eq 0 ]  
do  
let "remainder = dividend % divisor"  
dividend=$divisor  
divisor=$remainder  
done  
  
echo "НОД чисел $dnd и $dvs = $dividend"  

Результат выполнения скрипта:

ite@ite-desktop:~$ ./bash2_primer3.sh  
Введите числитель:  
100  
Введите знаменатель:  
90  
НОД чисел 100 и 90 = 10  

Математические операции

Команда let.
Команда let производит арифметические операции над числами и переменными.
Рассмотрим небольшой пример, в котором мы производим некоторые вычисления над введенными числами:

#!/bin/bash  
echo "Введите a: "  
read a  
echo "Введите b: "  
read b  
  
let "c = a + b" #сложение  
echo "a+b= $c"  
let "c = a / b" #деление  
echo "a/b= $c"  
let "c <<= 2" #сдвигает c на 2 разряда влево  
echo "c после сдвига на 2 разряда: $c"  
let "c = a % b" # находит остаток от деления a на b  
echo "$a / $b. остаток: $c "  

Результат выполнения:

ite@ite-desktop:~$ ./bash2_primer2.sh  
Введите a:  
123  
Введите b:  
12  
a+b= 135  
a/b= 10  
c после сдвига на 2 разряда: 40  
123 / 12. остаток: 3  

Ну вот, как видите ничего сложного, список математических операций стандартный:

+ — сложение
— вычитание
* — умножение
/ — деление
** — возведение в степень
% — модуль(деление по модулю), остаток от деления
let позволяет использовать сокращения арифметических команд, тем самым сокращая кол-во используемых переменных. Например: a = a+b эквивалентно a +=b и т.д

Работа с внешними программами при написании shell-скриптов

Для начала немного полезной теории.

Перенаправление потоков.

В bash (как и многих других оболочках) есть встроенные файловые дескрипторы: 0 (stdin), 1 (stdout), 2 (stderr).
stdout — Стандартный вывод. Сюда попадает все что выводят программы
stdin — Стандартный ввод. Это все что набирает юзер в консоли
stderr — Стандартный вывод ошибок.
Для операций с этими дескрипторами, существуют специальные символы: > (перенаправление вывода), < (перенаправление ввода). Оперировать ими не сложно. Например:

cat /dev/random > /dev/null #перенаправить вывод команды cat /dev/random в /dev/null (абсолютно бесполезная операция :)) )

или

ls -la > listing #записать в файл listing содержание текущего каталога (уже полезней)  

Если есть необходимость дописывать в файл(при использовании «>» он заменятеся), необходимо вместо «>» использовать «>>«

sudo < my_password

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

./program_with_error 2> error_file

цифра 2 перед «>» означает что нужно перенаправлять все что попадет в дескриптор 2(stderr).
Если необходимо заставить stderr писать в stdout, то это можно след. образом:

./program_with_error 2>&1

символ «&» означает указатель на дескриптор 1(stdout)
(Поумолчанию stderr пишет на ту консоль, в котрой работает пользователь(вренее пишет на дисплей)).

2. Конвееры.

Конвеер — очень мощный инструмент для работы с консолью Bash. Синтаксис простой:
команда1 | команда 2 — означает, что вывод команды 1 передастся на ввод команде 2
Конвееры можно группировать в цепочки и выводить с помощью перенаправления в файл, например:

ls -la | grep «hash» |sort > sortilg_list

вывод команды ls -la передается команде grep, которая отбирает все строки, в которых встретится слово hash, и передает команде сортировке sort, которая пишет результат в файл sorting_list. Все довольно понятно и просто.

Чаще всего скрипты на Bash используются в качестве автоматизации каких-то рутинных операций в консоли, отсюда иногда возникает необходимость в обработке stdout одной команды и передача на stdin другой команде, при этом результат выполнения одной команды должен быть неким образом обработан. В этом разделе я постораюсь объяснить основные принципы работы с внешними командами внутри скрипта. Думаю что примеров я привел достаточно и можно теперь писать только основные моменты.

1. Передача вывода в переменную.

Для того чтобы записать в переменную вывод какой-либо команды, достаточно заключить команду в `` ковычки, например

a = ` echo «qwerty» `
echo $a

Результат работы: qwerty

Однако если вы захотите записать в переменную список директорий, то необходимо, должным образом обработать результат для помещения данных в переменную. Рассмотрим небольшой, пример:

LIST=`find /svn/ -type d 2>/dev/null| awk '{FS="/"} {print $4}'| sort|uniq | tr 'n' ' '`  
for ONE_OF_LIST in $LIST  
do  
svnadmin hotcopy /svn/$ONE_OF_LIST /svn/temp4backup/$ONE_OF_LIST  
done  

Здесь мы используем цикл for-do-done для архивирование всех директорий в папке /svn/ с помощью команды svnadmin hotcopy(что в нашем случае не имеет никого значения, просто как пример). Наибольшй интерес вызывает строка: LIST=find /svn/ -type d 2>/dev/null| awk '{FS="/"} {print $4}'| sort|uniq | tr 'n' ' ' В ней переменной LIST присваивается выполнение команды find, обработанной командами awk, sort, uniq,tr(все эти команды мы рассматривать не будем, ибо это отдельная статья). В переменной LIST будут имена всех каталогов в папке /svn/ пгомещенных в одну строку(для того чтобы её стравить циклу.

Введение

Набор встроенных команд bash (и его аналогов sh, zsh, etc) совместим с любым POSIX-совместимым приложением в Linux, что позволяет встроить в ваш bash-скрипт любое совместимое приложение. Это дает очень большой набор возможностей в сфере автоматизации рутинных задач администрирования систем Linux, деплоя и сборки приложений, различных пакетных обработок, в том числе аудио и видео.

Командная строка — самый мощный пользовательский интерфейс из существующих на данный момент. Базовый уровень знаний получить достаточно просто. Рекомендуется изучить руководство bash. Это можно сделать, выполнив команду man bash.

Суть bash-скриптов — записать все ваши действия в один файл и выполнять их по необходимости.

В этой статье расскажем про написание bash-скриптов с нуля и получим представление, какую пользу можно из них извлечь. Рекомендуем держать под рукой bash-справочник, если вы планируете заняться этим всерьез.

Развертывание среды

Для выполнения скриптов, которые мы будем учиться писать, нужна среда. Если вы используете на своем компьютере систему Linux, вы можете делать все локально. Если Windows, — можете установить WSL/WSL2. Кроме того, вы можете создать виртуальный сервер и подключиться к нему по SSH. Так вы не навредите своему компьютеру если что-то пойдет не так.

Мы выбрали вариант создать виртуальную машину.  Залогинимся в личном кабинете https://my.selectel.ru/, нажав на вкладку «Облачная платформа». Там вы сможете создать виртуальный сервер.

Необходимо выбрать зону размещения сервера исходя из его близости к пользователям. Чем дальше сервер, тем выше пинг. 

Нажмем «Создать сервер». 

В разделе «Источник» убеждаемся, что выбран образ Ubuntu 20.04.

Конфигурацию можно настроить по своим потребностям.

В разделе «Сеть» стоит выбрать «Подсеть — Плавающий IP-адрес».

В разделе «Доступ» загрузите SSH-ключ и не забудьте сохранить root-пароль. Подробнее об этом рассказано в этой статье

Теперь можно создать сервер кнопкой «Создать» в самом низу.

Будет отображена страница статуса сервера, надо дождаться индикации ACTIVE вверху справа.

Теперь на вкладке «Порты» можно посмотреть IP-адрес, присвоенный серверу.

Не копируйте чужой код

Копирование чужого кода на свой компьютер/сервер опасно. Ранее существовал «патч Бармина», представляющий из себя команду rm -rf /*. Ее очень любили давать новичкам Linux на некоторых конференциях в качестве универсального средства от всех проблем. Суть команды — рекурсивное удаление всех каталогов внутри корневого каталога, т. е. всех системных и пользовательских файлов. Сейчас эта команда не сработает во всех актуальных версиях Linux, но раньше она служила злой шуткой и наказанием тем, кто копировал чужие скрипты на свои серверы и выполнял их. Способов навредить серверу/компьютеру все еще достаточно, но они не столь очевидны.

Выбор редактора

Вам потребуется удобный текстовый редактор. Если вы подключаетесь по SSH, то лучшим выбором будут 3 варианта:

  • * vim (если умеете из него выходить)
  • * nano (прост, удобен и надежен)
  • * mcedit (входит в пакет mc, классический двухпанельный консольный файловый менеджер)

Если вы делаете все локально, выбор полностью на вас. Обычный выбор под Linux — gedit. В этой инструкции мы пользовались nano через SSH на удаленном сервере.

Запуск “Hello, World!”

Первая программа, которую обычно пишут программисты это «Hello, World!» —  простой вывод этой строки. Мы тоже с этого начнем. За вывод строки в консоль отвечает команда echo. Прямо в консоли вы можете напечатать echo «Hello, World!» и получить соответствующий вывод:

    root@geneviev:~ # echo "Hello, World!"
Hello, World!

Сделаем это программой. Команда touch helloworld.sh создаст файл helloworld.sh. Команда nano helloworld.sh откроет этот файл для редактирования. Заполним файл нашей программой:

    #!/bin/bash
echo "Hello, World!"

Для выхода с сохранением из nano надо нажать CTRL + O для сохранения (после чего нажать enter для перезаписи текущего открытого файла), а потом CTRL + X для выхода. Можно выходить без сохранения, при этом он спросит, точно ли вы хотите выйти без сохранения. Если да, надо нажать N для выхода без сохранения. Если вы нажмете Y, он спросит куда сохранить измененный файл, можно нажать enter для перезаписи редактируемого файла.

Разберем, что мы написали.

Первой строкой идет #!/bin/bash — фактически это указание на местоположение интерпретатора. Чтобы при запуске скрипта не требовалось указывать отдельно интерпретатор. Убедиться, что ваш bash интерпретатор лежит по этому пути можно через команду which bash:

    root@geneviev:~ # which bash
/usr/bin/bash

Второй строкой идет непосредственно вся наша программа. Как она работает, мы разобрали выше, перейдем к выполнению.

Запустить ваш скрипт/команду можно двумя способами.

Способ №1: bash helloworld.sh. Вы вызываете интерпретатор и в аргументе передаете ему имя файла для исполнения.

    root@geneviev:~ # bash helloworld.sh 
Hello, World!

Способ №2: Сначала надо разрешить системе исполнять скрипт: chmod +x helloworld.sh. Эта команда сделает файл исполняемым. Теперь вы можете запустить его как любой бинарный файл в linux: ./helloworld.sh

    root@geneviev:~ # ./helloworld.sh 
Hello, World!

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

Аргументы

Это параметры, которые вы можете передать программе при ее вызове. Например, программа ping принимает в качестве обязательного аргумента IP-адрес или DNS-имя, которое требуется пропинговать: ping selectel.ru. Это простой и удобный способ общения пользователя с программой.

Давайте научим нашу программу принимать аргументы и работать с ними. Доступ к аргументам осуществляется через служебную команду $X где X это число. $0 — всегда имя исполняемого скрипта. $1 — первый аргумент, $2 — второй и так далее. Конечно, если вы планируете передавать пару десятков аргументов вашему приложению, это может быть несколько утомительно, так что вам понадобится что-то вроде этого цикла, чтобы перебрать все поступившие аргументы:

    for var in "$@"; do
    echo "$var"
done

Подробнее про циклы будет рассказано в следующих разделах.

Пример, создадим новый файл: touch hellousername.sh. Выдаем права на исполнение chmod +x hellousername.sh.

Открываем nano hellousername.sh

Код примера следующий:

    #!/bin/bash 

echo "Hello, $1!"

Сохраняем, закрываем. Смотрим, что получилось.

    root@geneviev:~ # ./hellousername.sh Vasya
Hello, Vasya!

Программа получилась маленькая, но она учит пользоваться (на самом базовом уровне) аргументами, которые мы в нее можем передать. В данном случае аргумент передается один, Vasya, мы сразу его используем, не делая никаких проверок. 

    root@geneviev:~ # ./hellousername.sh 
Hello, !

При таком сценарии в нашей программе баг: она ни с кем не поздоровается. Чтобы исправить ситуацию, есть 2 способа: проверить число аргументов или проверить содержимое аргумента.

Способ №1

    #!/bin/bash
if [ "$#" -lt 1 ]; then
    echo "Недостаточно аргументов. Пожалуйста, передайте в качестве аргумента имя. Пример: $0 Vasya"
    exit 1
fi
echo "Hello, $1!"

Более подробно конструкцию if then [else] fi мы рассмотрим далее, пока не будем на ней останавливаться. Важно понимать, что тут проверяется. $# Это число аргументов без учета имени скрипта, который всегда $0. 

Способ №2

    #!/bin/bash
if [ -z "$1" ]; then
   echo "Имя пустое или не передано. Пожалуйста, передайте в качестве аргумента имя. Пример: $0 Vasya"
   exit 1
fi

echo "Hello, $1!"

Здесь тоже используется конструкция if then [else] fi. Ключ -z в if используется для проверки переменной на пустую строку. Есть противоположный ключ -n, он проверяет что строка не пустая. Конечно, этот способ некорректно использовать для проверки входящих аргументов, но в теле самой программы он будет полезен. Например, чтобы проверить что выполненное в самой программе приложение что-то вернуло.

Управляющие конструкции

if-else

Написание программ на любом из языков длиннее нескольких строчек сложно представить без ветвления. В разных языках бывают разные варианты ветвления, но в большинстве случаев используется синтаксис if else. В bash это также присутствует.

Возьмем один из примеров выше.

    #!/bin/bash
if [ "$#" -lt 1 ]; then
    echo "Недостаточно аргументов. Пожалуйста, передайте в качестве аргумента имя. Пример: $0 Vasya"
    exit 1
fi
echo "Hello, $1!"

Происходит проверка системной переменной $# на то, что она меньше, чем (lower than, -lt) 1. Если это выражение истинно, мы переходим в блок команд, открывающийся ключевым словом then. Весь блок, начинающийся с if, должен завершаться ключевым словом fi. Более сложная структура ветвления может выглядеть примерно так:

    if TEST-COMMAND1
then
  STATEMENTS1
elif TEST-COMMAND2
then
  STATEMENTS2
else
  STATEMENTS3
fi

Реальный пример:

    #!/bin/bash
if [ "$#" -lt 1 ];
then
    echo "Недостаточно аргументов. Пожалуйста, передайте в качестве аргумента имя. Пример: $0 Vasya"
    exit 1
fi
if [ "$1" = "Vasya" ]; then
        echo "Whatsupp, Vasiliy?"
elif [ "$1" = "Masha" ];
then
        echo "Hey, Masha"
elif [ "$1" = "Michael" ];
then
        echo "Shalom, Michael"
else
        echo "Hi, $1"
fi

Вывод программы:

    root@geneviev:~ # ./hellousername.sh Vasya
Whatsupp, Vasiliy?
root@geneviev:~ # ./hellousername.sh Masha
Hey, Masha
root@geneviev:~ # ./hellousername.sh Michael
Shalom, Michael
root@geneviev:~ # ./hellousername.sh Andrew
Hi, Andrew
root@geneviev:~ # ./hellousername.sh 
Недостаточно аргументов. Пожалуйста, передайте в качестве аргумента имя. Пример: ./hellousername.sh Vasya

Выражение «$1» = «Vasya» проверяет строки на идентичность. Блок после else выполняется только если выше не найден более подходящий блок.

&& и ||

В предыдущей главе вы могли заметить, что я использовал exit 1 для завершения работы программы в случае неуспешной проверки аргумента. Это означает, что программа завершилась с ошибкой. В bash есть операторы && и ||, которые используются для создания цепочек команд. Каждая цепочка зависит от результата выполнения предыдущей программы.

Пример 1: command1 && command2. В этом случае command2 выполнится, только если command1 завершится с кодом 0 (exit 0, по умолчанию). 

Пример 2: command1 || command2. В этом случае command2 выполнится, только если command1 завершится с кодом отличным от 0. 

Пример 3: command1 && command2 || command3. Если command1 завершится с кодом 0, то будет выполнен command2, иначе command3.

Переменные

Как гласит один из основных принципов программирования — Do Not Repeat Yourself (DRY). Вот и мы не будем повторять себя и перепишем предыдущий пример с использованием переменных, чтобы не вызывать echo каждый раз.

Переменные в bash создаются присваиванием: x=»foo bar» или z=$1. Переменной x мы присвоили строку @foo bar«, а переменной z мы присвоили значение первого аргумента. Использовать именованные переменные гораздо удобнее, чем использовать $1, особенно когда надо использовать его значение во многих местах.

К тому же, аргументы могут идти в разном порядке. Осмысленные названия переменных очень важны, при разрастании программы это снизит неизбежную путаницу. Избегайте имен переменных (и функций) вроде «a», «b», «zzzz», etc.

Чтобы не вызывать echo в каждом варианте с разными строками, разобьем строку на части. Первая часть будет приветствием. Вторая — именем. Третья — завершающим знаком препинания. Его можно не выносить в переменную.

    #!/bin/bash

greetString="Hello"
nameString="stranger"

if [ "$#" -lt 1 ];
then
    echo "Недостаточно аргументов. Пожалуйста, передайте в качестве аргумента имя. Пример: $0 Vasya"
    exit 1
fi

if [ "$1" = "Vasya" ]; 
then
    nameString="Vasiliy"
	greetString="Whatsup"
elif [ "$1" = "Masha" ];
then
	nameString="Maria"
elif [ "$1" = "Michael" ];
then
	greetString="Shalom"
	nameString="Michael"
fi

echo "$greetString, $nameString!"

В этом примере мы создаем переменные greetString и nameString, которым присваиваем значения по умолчанию. В конце программа выводит значения этих двух переменных с помощью echo и форматированной строки (в двойных кавычках переменные раскрываются). Между этими действиями программа определяет, надо ли присваивать переменным другие значения.

Switch case

Использование if-else конструкции в нашем примере не является оптимальным вариантом. Мы всего лишь сверяем значение переменной с определенным набором значений. В такой ситуации лучшим выбором будет switch-case-конструкция.

    case "$variable" in

 "$condition1" )
 command...
 ;;

 "$condition2" )
 command...
 ;;

esac

Перепишем нашу программу приветствий с использованием switch-case:

    #!/bin/bash

name=$1

case "$name" in
  "Vasya" )
    nameString="Vasiliy"
	greetString="Whatsup"
  ;;
  "Masha" )
	greetString="Hey"
	nameString="Maria"
  ;;
  * )
	greetString="Hello"
	nameString="stranger"
  ;;
esac

echo "$greetString, $nameString!"

Циклы

Как и любой полноценный язык программирования, bash поддерживает циклы. Цикл for и цикл while. Циклы нужны, чтобы выполнять какой-то код заданное число раз. Например, при парсинге CSV перебирать построчно и каждую строку рассматривать отдельно.

Цикл for

Вот пример структуры цикла for:

    for var in list
do
команды
done

Простой реальный пример:

    #!/bin/bash

for name in Maria Vasya Michael stranger
do
	echo "Hello, $name!"
done

Вывод:

    root@geneviev:~ # ./cycle.sh 
Hello, Maria!
Hello, Vasya!
Hello, Michael!
Hello, stranger!

Программа просто перебирает все имена, разделенные пробелом, и выводит их с помощью echo.

Попробуем немного усложнить пример:

    #!/bin/bash
file=$1
for name in $(cat $file)
do 
	echo "Hello, $name!"
done

Создадим файл с именами touch names и запишем в него список имен для приветствия:

    Maria
Vasiliy
Ivan
Nikolai
Innokentiy

Вывод:

    root@geneviev:~ # ./cycle.sh 
^C
root@geneviev:~ # ./cycle.sh names
Hello, Maria!
Hello, Vasiliy!
Hello, Ivan!
Hello, Nikolai!
Hello, Innokentiy!

Обратите внимание на ^C. Это символ прерывания выполнения программы. В нашем случае мы вызвали программу без аргумента, и она вошла в вечный цикл. Можно сказать, зависла. Пришлось завершить ее принудительно. Не забывайте делать проверки входных данных в реальных программах.  Как это делать, можете посмотреть в главах if-else и switch case, например.  

В нашей программе есть небольшой баг. Модифицируем файл имен:

    Erich Maria Remarque
Vasiliy
Ivan
Nikolai
Innokentiy

Запустим программу, получим вывод:

    root@geneviev:~ # ./cycle.sh names
Hello, Erich!
Hello, Maria!
Hello, Remarque!
Hello, Vasiliy!
Hello, Ivan!
Hello, Nikolai!
Hello, Innokentiy!

Как говорится, «Кто все эти люди?». Так получается, потому что у нас не задана переменная окружения IFS (Internal Field Separator), указывающая на разделители полей. Наш цикл использует пробелы и переносы строки как разделители. В начале скрипта (после #!/bin/bash) укажите использовать перенос строки как разделитель полей: IFS=$’n’

    root@geneviev:~ # ./cycle.sh names 
Hello, Erich Maria Remarque!
Hello, Vasiliy!
Hello, Ivan!
Hello, Nikolai!
Hello, Innokentiy!

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

Обычно цикл for используется со счетчиком. В C-like стиле. Что-то вроде for (i=0;i<10;i++){}. В bash тоже так можно. 

    #!/bin/bash
for (( i=1; i <= 10; i++ ))
do
echo "number is $i"
done
 
Вывод:
 
root@geneviev:~ # ./cycle.sh 
number is 1
number is 2
number is 3
number is 4
number is 5
number is 6
number is 7
number is 8
number is 9
number is 10

Цикл while

Схема организации цикла while:

    while команда проверки условия
do
другие команды
done

Простой способ сделать бесконечную петлю (бесконечный цикл):

    while true
	do
	echo "this is infinity loop"
done

Это может пригодится, например, когда вам нужно вызывать что-то чаще, чем позволяет cron (например, раз в минуту). Или когда вам просто надо проверять какое-то значение постоянно. Областей применения у бесконечных циклов много.

Здесь используются те же самые выражения, что и в if:

    #!/bin/bash
count=0
while [ $count -lt 10 ]
do
	(( count++ ))
	echo "count: $count"
done

Вывод:

    root@geneviev:~ # ./cycle.sh 
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
count: 7
count: 8
count: 9
count: 10

Из цикла можно выйти с помощью команды break (работает также и для for):

    #!/bin/bash
count=0
while [ $count -lt 10 ]
do
	(( count++ ))
	echo "count: $count"
	if [ "$count" -gt 5 ]
	then
		break
	fi
done

Вывод:

    root@geneviev:~ # ./cycle.sh 
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6

Заключение

Несмотря на огромную конкуренцию в сфере автоматизации рутины со стороны python, ruby, perl bash не сдает позиции. Он прост в освоении и использовании, гибок и так или иначе присутствует в абсолютном большинстве дистрибутивов Linux.

В этой статье были приведены только основы написания программ на bash. Надеемся, вы нашли их полезными для себя.

Активные пользователи компьютера время от времени сталкиваются со словом «скрипт», не всегда понимая, что же оно значит. В рамках сегодняшнего материала я отвечу на этот вопрос, приведу несколько примеров того, как и с помощью чего создаются скрипты, а также расскажу, можно ли самостоятельно написать какой-нибудь скрипт и запустить его для выполнения задачи.

Общее понимание скрипта

С английского языка слово «скрипт» переводится как сценарий, из чего уже можно сделать определенные выводы. Это набор команд, то есть строк кода, которые вкупе выполняют конкретную задачу. Для ее выполнения и создаются скрипты. Они могут быть как очень маленькими по объему и отвечать за запуск каких-то простых служб операционной системы, так и объемными, сравнивая переменные и выводя результат на сайте.

Скрипт JavaScript

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

Скрипты сейчас активно интегрируются на сайтах, в качестве примера можно привести популярный скриптовый язык – JavaScript. Однако изначально они работали в операционных системах и выполнялись при помощи внутреннего синтаксиса командной оболочки.

История появления скриптов

Для общего развития предлагаю немного окунуться в историю появления скриптов и взглянуть на то, какими они были раньше. Начали применять их под управлением семейства операционных систем Unix еще 50 лет назад. Одной из первых командных оболочек была sh, в ней использовались shell scripts, которые позволяли выполнять самые разнообразные задачи на компьютере.

SH для написания скриптов в Unix

Ниже вы видите небольшой код, предназначенный для конвертирования изображения из JPG в PNG:

for jpg; do # использовать $jpg для каждого имени файла по очереди

    png="${jpg%.jpg}.png"                    # получить PNG-версию имени файла .jpg с .png

    echo converting "$jpg" ...               # сообщение для пользователя

    if convert "$jpg" jpg.to.png ; then      # использовать утилиту convert для создания временного PNG-файла

        mv jpg.to.png "$png"                 # если сработало, переименовать временный PNG-файл, дав требуемое имя

    else                                     # ...иначе напечатать сообщение об ошибке

        echo 'jpg2png: ошибка: результат сохранен в "jpg.to.png".' >&2

        exit 1

    fi                                       # конец "if"

done # конец "for"

echo "Успешно преобразовано" # сообщение об успехе

exit 0

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

Сферы использования скриптов

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

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

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

Если говорить о Windows, то в ней вы можете найти встроенный инструмент CMD (PowerShell), который и предназначен для запуска скриптов, хранящихся в формате BAT.

Самостоятельное написание и применение скриптов

Разберем самостоятельное написание и применение скриптов на примере Windows. Допустим, у вас стоит задача проверить стабильность соединения с конкретным сайтом без запуска браузера. Для этого есть одна полезная команда, запускаемая через Командную строку. А если нужно еще сформировать и отчет о результатах проверки, не совсем удобно будет вводить несколько разных команд по очереди, особенно в тех случаях, когда задача выполняется раз в несколько дней или чаще. Тогда создается BAT-файл с таким содержимым:

@echo off

:start

ping -n 5 yandex.ru | find "TTL=" > nul

if %errorlevel%==1 (

    echo Ping No on IP yandex.ru Data: %date% %time% >>Result.txt

    ) else (

        echo Ping Yes on IP yandex.ru Data: %date% %time% >>Result1.txt

        )

timeout /T 5 /NOBREAK

goto :start

Этот скрипт анализирует доступ к сайту yandex.ru и создает отчет на рабочем столе. Попробуйте создать простой текстовый файл, внести туда этот код, поменять адрес сайта и сохранить файл с расширением .bat. Запустите его и посмотрите, что получится в итоге.

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

  • Wikipedia programs
  • Bots
  • Extensions
  • Gadgets
  • User scripts
    • List
    • Ranking
    • Requests
    • Guide
    • Other scripts
  • Tools
  • WP:US/G

This page is about writing user scripts for use on Wikipedia. For instructions on how to install user scripts, see How do you install user scripts?

Prerequisites[edit]

To write user scripts, you’ll have to learn at least some of the programming language that they are written in: JavaScript.

Try these links:

  • Mozilla Developer Network’s JavaScript site
  • W3schools Javascript tutorial
  • JavaScript syntax
  • jQuery

Also, it would definitely help if you tried using one of our scripts and got it working. The rest of this tutorial assumes you know where the various things are (all explained at Wikipedia:User scripts#How do you install user scripts?).

Forking an existing script[edit]

Starting out, it may be easier to modify an existing script to do what you want, rather than create a new script from scratch. This is called «forking». To do this, copy the script to a subpage, ending in «.js»,[n. 1] of your user page. Then, install the new page like a normal user script.

Writing a script from scratch[edit]

While you can write a script directly in your common.js page or skin.js (such as vector.js) page, it is usually better to create a new subpage for it in the form YourUserName/title.js, where title is the name of your script. That keeps your main js pages from getting cluttered, which is helpful when you have multiple scripts installed. You will also want to install the new user script.

Hello world[edit]

To make a Hello world program, insert this code into your User:YourUserName/common.js file.

importScript('User:YourUserName/hello-world.js');

Next, create the page User:YourUserName/hello-world.js, and insert this code.

$('#bodyContent').prepend('<p>Hello world!</p>');

This will write «Hello world!» on every page, below the title, until you remove the code. This uses JQuery, although you could also write this in pure JavaScript. #bodyContent is a selector that lets us reference the HTML element we want. prepend inserts HTML code as a child of the #bodyContent element, at the beginning.

Your first script[edit]

We will be writing an independent module by modifying your js, so you may want to get our module template. For the purpose of this tutorial, we will write a simple version of the Quick wikify module, which adds the {{Wikify}} maintenance template to articles. To begin, change MODULE_NAME in the module template to «Qwikify». Your template should look like this:

// Qwikify
$(document).ready( function () {
    MODULE_CODE;
} );

In MODULE_CODE, we want to add the «Wikify» tab, so we will use the addPortletLink function (which requires «mediawiki.util» module). Replace MODULE_CODE with a call to this function. Then we’ll bind an event handler so that when this link is clicked, we will call another function named doQwikify() that will actually execute the code. The name is what is shown on the tab, so set that to "Wikify". Most tabs have an id of «ca-(their name)», so set the id to "ca-wikify". The title (also known as mouseover or rollover text) should be something like "Mark for wikification". Lastly, we use jQuery’s .click() to listen for clicks on this link, and when that happens execute a function. After we call doQwikify(), it says event.preventDefault(). Since we clicked on a link, we need to tell the browser to prevent its default behavior (which is going to a the url, ‘#’). We want the page to stay right where it’s at, so to prevent the browser from following the link, we prevent that and do our own custom action.

Altogether, your new function should look like this:

// Make sure the utilities module is loaded (will only load if not already)
mw.loader.using( 'mediawiki.util', function () {

    // Wait for the page to be parsed
    $( document ).ready( function () { 

        //see below "Portlets" subsection
        var link = mw.util.addPortletLink( 'p-cactions', '#', 'Wikify', 'ca-wikify', 'Mark for wikification'); 
        $( link ).click( function ( event ) {
            event.preventDefault();
            doQwikify();

        } );
    } );
} );

Now, we must write our actual doQwikify() function. It will edit the edit box, so we need to get the name of that and its form. Viewing the source of the page shows that the form is named editform and the textbox is named wpTextbox1, meaning that the actual text is document.editform.wpTextbox1.value. To add {{wikify}} (and two new lines), we simply do:

document.editform.wpTextbox1.value = "{" + "{wikify}}nn" + document.editform.wpTextbox1.value;

(We separate the two «{» brackets in the front of the wikify template so it doesn’t get expanded when we write this code on the wiki.)

Finally, we want to submit the form for the user. Luckily, JavaScript has a built-in function just for this named submit(). To submit our editing form, use document.editform.submit(). Your code should now look something like this:

function doQwikify() {
    document.editform.wpTextbox1.value = "{" + "{wikify}}nn" + document.editform.wpTextbox1.value;
    document.editform.submit();
}

And that’s it! Save the common.js and then do a hard refresh. Go and edit a page such as the Sandbox, and see what happens![1]

On load/document ready function[edit]

The personal «user» module (built from /common.js, /common.css and optionally the skin-specific files for the current skin) and gadgets are loaded on all pages. Most scripts will want to manipulate elements on the page; to do so the page needs to be ready (which may not be the case at the time the modules are loaded). We can defer execution of code by using a special function. Most commonly .ready() from jQuery.

// Define our main function
function myScript() {
  // ... code ...
};

// Schedule it to run after the HTML page is parsed
$( document ).ready( myScript );

// This shorthand is also valid
jQuery( myScript );

Since the function is called only once, many users prefer to shorten this code with an anonymous function:

$( document ).ready( function () {
  // ... code ...
} );

// Or
jQuery( function () {
  // ... code ...
} );

Note: $ and jQuery are the same object; choosing between them is purely a matter of opinion.

Many scripts use this function simply to add some script interface, such as a link in a portlet. Then the main part of the code is executed after the user clicks on that link.

Built-in scripts[edit]

All Wikipedia pages include some built-in MediaWiki JavaScript code, with variables and functions that can be used in user scripts. The specific code depends on the viewed page and current users, for more details see Wikipedia:Catalogue of CSS classes#Stylesheets and JavaScript.

Of most interest are:

  • Available ResourceLoader modules (mw.*)
    • mw.config variables
  • MediaWiki:Common.js (managed by local administrators)
  • The user’s own general /common.js
  • The user’s own skin-specific /skin.js (exact name depends on the skin in the user’s preferences)

Development and testing[edit]

The following development environments can be used to develop and test your script.

Basic[edit]

  • Using the preview button: You can edit your script directly on your /common.js page, then click [Show preview] and the new code is executed right away on the preview page.
  • Saving it: If required elements are missing on the preview page (for example, your script does something on history pages), you will have to save the script in order to test it. However, it’s not convenient and creates unnecessary entries in the page history.
  • Execute it in your browser’s JavaScript console: All modern browsers come with a JavaScript console and other development tools. You can type or paste and execute your code there; script errors and warnings will also be shown there. How to open the console depends on your browser:
    • In Google Chrome and Edge – press Ctrl+⇧ Shift+J
    • In Firefox – press F12
    • In Safari – press Ctrl+Alt+C
You may need to click the Console tab if a different pane is currently open.

Loading it from a localhost web server[edit]

The best and most recommended way to load a JavaScript file during development is from your local web server (see below for an easy way to install a web server). Put this string in your /common.js:

mw.loader.load( 'https://localhost/wikipediatest.js' );

In some environment, you need write this like[2]:

mw.loader.load( 'http://127.0.0.1/wikipediatest.js' );

Then run any web server on your computer and create the wikipediatest.js file in the appropriate folder. The code inside this file will be executed as if it was inside your personal script.

You can edit your wikipediatest.js file with any text editor, perhaps with syntax highlighting and other convenient features, save the file and simply reload any Wikipedia page to see the results. (You don’t need to wait, and if your web server is nice or you set it right, you don’t even need to bypass your browser cache.)

Most modern code editors and IDEs allow you to set up a localhost server – eg. use atom-live-server in Atom, and Live Server in VS Code. WebStorm and PhpStorm have the feature built in, without requiring an extension. You can also use a third party program such as Node.js’s npx http-server command, or XAMPP. Here is a video tutorial of the Node.js method.

On Windows, you could also use for example TinyWeb which is less than 100 kbyte on disk and doesn’t require installation. Save and unzip tinyweb.zip for example into c:Program FilesTinyweb, create a shortcut to tiny.exe, and add an argument in shortcut properties — path to your folder with wikipediatest.js and any file index.html (required). Start TinyWeb with this shortcut; unload it with Task Manager.

Note that this method doesn’t work in Opera 9.50 (and later) due to added security restrictions, see Opera 9.50 for Windows changelog: «Local servers can use remote resources, but not vice versa». In Chrome, it may be necessary to enable SSL, otherwise the script will refuse to load.

Browser-specific[edit]

Some browsers allow you to automatically execute your JavaScript code on specific web pages. This way you don’t have to be logged in to Wikipedia. One example is Tampermonkey. However, making user scripts work with one of these extensions might require some modifications to the script code.

Running pieces of code[edit]

You can run pieces of code on already loaded pages via the JavaScript console. See the guide for doing this in Chrome. It works similarly in most other browsers.

Publishing[edit]

Once you have finished the user script code, you can save it as a page so that others can import it. By convention, scripts are in your userspace and have titles ending in «.js»,[n. 1] for example «User:YourUsernameHere/MyCoolScript.js». Others can then install the new script.

Text editors and debugging[edit]

Text editors[edit]

You can use anything from a simple text editor, to a more feature-packed code editor or IDE. Here are some features we recommend:

  • Color code JavaScript code
  • Quickly insert standard JavaScript keywords and methods with Ctrl+↵ Enter
  • Show the list of all functions and quickly jump to any function
  • Code folding
  • If you plan to use non-ASCII characters in string, your text editor should support UTF-8.

Here are some recommended editors, by operating system.

  • Windows
    • VS Code (cross-platform)
    • Notepad++
  • Mac OS X
    • Xcode
    • JEdit (cross-platform)
    • Komodo Edit (cross-platform)
    • Aptana Studio (cross-platform)
    • TextMate (not free)
    • Coda (not free)
    • PhpStorm (not free, cross-platform, a free license for MediaWiki Developers is also available[3])
  • Linux
    • gedit (may come with Linux)
    • Kate (may come with Linux)

JavaScript Debuggers[edit]

These are typically built into browsers, in their DevTools window. Debuggers allow you to step debug (go through your JavaScript code line-by-line, hover over variables to see their values, etc.)

  • Firefox — use Tools → JavaScript Console which shows all JavaScript and CSS errors.[n. 2]
  • Chrome and Chromium — use Tools → Developer Tools.
  • Safari — Safari → Preferences → Advanced and enable the «Show Develop menu in menu bar» option. Then use Develop → Show Web Inspector to open up the development tools.
  • Opera — use Tools → Advanced → Error Console which shows all JavaScript and CSS errors.[n. 3]

Basic techniques[edit]

Finding elements[edit]

Every HTML element is a node in a DOM model which allows scripts to access the element, for example, on the following HTML page.

<form name="frmname" id="frmid">
	<textarea name="txtname" id="txtid"></textarea>
	<input id="neighbor" />
</form>

We can find element textarea:

  • Using its id: $( '#txtid' )
  • In the array of all elements with the same tag: $( 'textarea' )
  • Using an element next to it: $( '#neighbor' ).prev()
  • As a child of its parent: $( '#frmid' ).children( 'form' )
  • As a form element, using name: $( '#frmid [name="txtname"]' )

This example on jsFiddle

The jQuery API reference is an excellent source for documentation.

Checking the current page[edit]

Many scripts are supposed to work only on some pages. You can check:

  • The page type
if ( mw.config.get( 'wgAction' ) === 'history' ) {  // Continue only on history pages.
  • wg (Wikimedia global) variables; many of them have the same meaning as Magic words
if ( mw.config.get( 'wgCanonicalNamespace' ) === 'User_talk') {  // Continue only on User_talk pages.
if ( mw.config.get( 'wgPageName' ) === 'Article_name' ) {  // Continue only for the article "Article name".
  • Presence of elements (only in second and third parts of the script)
function func_start() {
   if ( $( '#editForm' ).length == 0  ) return; //No edit form  ? exit
   // …

Portlets (menus and tabs)[edit]

  • WP:PORTLET

Portlets are MediaWiki’s name for groups of links located in the topbar and sidebar. Here is a diagram of portlet ID’s.

List of portlets[edit]

  • Top
    • p-personal — The links at the very top right of the page. «personal» stands for «personal tools».
    • p-namespaces — The tabs on the left that never collapse. Not recommended, not much space. The article and talk tabs are located here.
    • p-views — The tabs in the middle that never collapse. Not recommended, not much space. The favorite page star tab is located here.
    • p-cactions — The items in the «More» tab’s dropdown menu. «cactions» stands for «content actions».
    • p-search — Adding things here will mess up the appearance of the search box. Not recommended.
  • Left
    • p-logo — Adding things here will mess up the appearance of the logo. Not recommended.
    • p-navigation
    • p-interaction — Has the title «Contribute».
    • p-tb — Has the title «Tools». TB stands for toolbox.
    • p-coll-print_export — Has the title «Print/export». Not a good place to add things, since this should just be for printing and exporting.
    • p-wikibase-otherprojects — Has the title «In other projects». Not a good place to add things, since this should just be for links to other projects such as Wikisource, Wikibooks, etc.
    • p-lang — Has the title «Languages». Not a good place to add things, since this should just be for languages.

Portlet structure[edit]

<div id="p-myname" class="portlet">
 <h5>Header</h5>
 <div class="body">
  <ul>
  <li id="…"> <a >  //Links
  <li id="…"> <a >
  … …

Adding elements[edit]

There is a special function in mediawiki.util.js that simplifies the process of adding your own links to portlets. The advantage of using this function is that your code should work across all skins.

mw.util.addPortletLink(

  • portletType,
  • linkURL, — set to # if you don’t need to open a page, and want to use a JavaScript listener instead
  • linkText,
  • elementID, (optional) — suggest using a prefix such as ca-, pt-, n-, or t-
  • tooltip, (optional)
  • keyboardShortcutKey, (optional) — set to null if you don’t need it [1]
  • nextNode, (optional) — element that this will be added in front of

);

// Several examples of portlet links

// Adds a link to your js file to the toolbox. tb = toolbox
mw.util.addPortletLink ( 'p-tb', mw.util.getUrl( 'Special:MyPage/common.js' ), 'My JS', 'pt-myvector', 'Visit your js file');

// Add a link to the edit page for your Notes in your personal links
// Note: We assume that short/pretty URLs are in use with ?action, ideally you would check for that.
mw.util.addPortletLink ( 'p-personal', mw.util.getUrl( 'Special:MyPage/Notes' ) + '?action=edit', 'My notes', 'pt-mynotes', 'Edit your personal notes' );

// Adds a link to prefix index for the current page to the toolbox
mw.util.addPortletLink ( 'p-tb', mw.util.getUrl( 'Special:Prefixindex/' + mw.config.get( 'wgPageName' ) ), 'Prefixindex', 'tb-prefixindex');

// Adds a link to logs for your account
mw.util.addPortletLink ( 'p-personal', mw.util.getUrl( 'Special:Log/' + mw.config.get( 'wgUserName' ) ), 'My logs', 'pt-mylogs');

Or you can use JQuery. Simply attach it in another place with .append(), .prepend(), .before(), or .after(). [2][3]. Warning: This is very fragile. You may get it working on a couple skins, but a couple other skins may look broken.

// Add a clickable button on the edit article page, above the edit summary.
$('.editOptions').prepend('<button type="button" id="my-custom-button">Do Things</button>');

// Add a listener to your button, that does something when it is clicked.
$('#my-custom-button').click(function(e) {
	// do things
});

Removing elements[edit]

To hide an element, you can use JQuery’s .hide() function.

// Example: remove special characters toolbar from edit page
$( '#editpage-specialchars' ).hide();

// Or modify the CSS directly
$( '#editpage-specialchars' ).css( 'display', 'none' );

Or you can do it by placing code in common.css:

#editpage-specialchars {
	display:none;
}

Editing[edit]

Textarea with article wikicode[edit]

The most important element on the edit page is a <textarea> with the article text inside. You can reference it with

var $textbox = $( '#wpTextbox1' );

You can manipulate it using the jquery.textSelection ResourceLoader module.

var $textbox = $( '#wpTextbox1' );
$textbox.textSelection( 'setContents', 'This is bold!' );
$textbox.textSelection( 'setSelection', { start: 8, end: 12 } );
$textbox.textSelection( 'encapsulateSelection', { pre: '<b>', post: '</b>' } );
// Result: Textbox contains 'This is <b>bold</b>!', with cursor before the '!'

Or you can grab <textbox>‘s text, create a string, modify it, then write it back. Note; other editing tools might not recognise your changes or cause conflicts if you use this methodology instead of the textSelection api.

// Get value.
let value = $('#wpTextbox1').val();

// Your code goes here. Do things to value. RegEx, .replace(), concatenate, etc.

// Then write it back.
$('#wpTextbox1').val(value);

Editing toolbar[edit]

WikiEditor is now the default toolbar when editing the source code of articles, but some users are still using the original toolbar. You can turn on and off WikiEditor by checking and unchecking the «Enable the editing toolbar» check box in your preferences.[n. 4][n. 5]

Edittools[edit]

There is another edit panel under textarea. Usually it’s generated from MediaWiki:Edittools by Extension:CharInsert and consists of a lot of JavaScript links. In the English Wikipedia, this approach was replaced by MediaWiki:Gadget-charinsert.js and MediaWiki:Gadget-charinsert-core.js.

Doing something after another user script[edit]

Sometimes you may want to add or remove something from the DOM, but another user script edits the same area of the DOM. It can be random which user script finishes first, creating a race condition.

One way to coordinate this is use the mw.hook interface. Perhaps the other script sends a wikipage_content event when it’s done, or can be modified to do so (or you can ask the maintainer).

Another way to avoid this is to use the DOMNodeInserted or DOMNodeRemoved events to listen for when the other user script is finished, ensuring that your user script executes last.

$('body').on('DOMNodeInserted', '.preferences-link.link', function() {
    // do things
}

User settings[edit]

If you want your users to be able to manually set configuration variables, one way to do this is to have them place window.scriptNameSettingName = 'value here'; in their common.js file. Then within your user script, you can read this value with if ( window.scriptNameSettingName == 'value here' ).

Notice that «scriptName» is one of the pieces of the variable name. This is important to help make sure the variable is unique.

Do not use let scriptNameSettingName = 'value here'; in the common.js file. If the user forgets the setting, you may get undeclared variable errors.

If you want your user script to write and save configuration settings while it is running, you may want to have it write to its own .js file in the user’s userspace. See twinkleoptions.js or redwarnConfig.js for examples.

Preventing bugs[edit]

<nowiki> tags[edit]

You may want to place the following code at the top and bottom of your user script, in a comment. This will help prevent bugs, such as ~~~~ turning into your signature when you update your code.

//<nowiki>

Your code here.

//</nowiki>

Function scope[edit]

Don’t declare named functions in the global namespace. For example, this is bad:

function submitEdit() {/* do stuff */}

$(function{/* main code here */});

What if another of your user scripts also declares a submitEdit() function, but you have modified the code? This can lead to race conditions and hard-to-trace bugs. Instead, use classes named after your script, or place all your functions inside of $(function {});. JavaScript allows nested functions.

$(function{
    function submitEdit() {/* do stuff */}
    
    /* main code here */
});

Ajax[edit]

AJAX (asynchronous JavaScript and XML) is a popular name for a web programming technique that queries the server or fetches content without reloading the entire page.

While programming AJAX can be complex, libraries of functions can make it much easier. Since the 1.16 release, MediaWiki comes with the jQuery library, which provides a convenient framework for easily making Ajax requests.

Common problems[edit]

  • AJAX programmers commonly run into problems if they don’t account for AJAX’s asynchronicity. If you try to pop up a box with another page’s content, you will almost certainly pop up a box containing null. This occurs because the script continued even though the query wasn’t finished.

    To correct the problem, you need to use callback functions. Place the next portion of code after a query into a function, and call the function when the query completes. jQuery makes this very easy to do.

  • AJAX scripts cannot reach a page on a different server (for example, google.ca or en.wikisource.org from en.wikipedia.org). Trying to do so will cause the script to halt with or without error. This can be circumvented using a proxy on the current server, but none is available for Wikimedia user scripts.

Basic examples[edit]

MediaWiki provides some modules with helper functions which facilitate the use of its API. The main modules available are

  • mediawiki.api

If your script makes use any method or code provided by these modules, remember to indicate the dependencies with mw.loader.using or, in case of gadgets, on its definition at MediaWiki:Gadgets-definition.

This API has several advantages especially when dealing with POST requests. It provides automatic token refresh and retry, handles various error situations and does parameter request building for several common use cases like rolling back a revision.

Be sure to follow the user agent policy by setting a user agent header (see code there). See also mw:API:Etiquette.

Fetch page content[edit]

Fetching a page content can be done using GET.

$.ajax({
	url: mw.util.getUrl( 'Wikipedia:Sandbox' )
})
.then(function( data ) {
	alert( 'The remote page contains:n' + data );
})
.catch(function() {
	alert( 'The ajax request failed.' );
});

Get the wikitext of a page[edit]

Using module mediawiki.api[edit]

Note: make sure to add «mediawiki.api» to your dependencies!

function doSomethingWithText( wikitext ) {
	/* .. */
	alert( 'The wikitext of the page is:nn' + wikitext );
}
function doSomethingInCaseOfError () {
	/* .. */
	console.log( 'err' );
}
(new mw.Api()).get( {
	prop: 'revisions',
	rvprop: 'content',
	rvlimit: 1,
	indexpageids: true,
	titles: 'Wikipedia:Sandbox'
} )
.then( function ( data ) {
	var q = data.query,
		id = q && q.pageids && q.pageids[0],
		pg = id && q.pages && q.pages[ id ],
		rv = pg && pg.revisions;
	if ( rv && rv[0] && rv[0]['*'] ) {
		doSomethingWithText( rv[0]['*'] );
	}
} )
.catch( doSomethingInCaseOfError );
Using plain jQuery[edit]
$.getJSON(
	mw.util.wikiScript('api'),
	{
		format: 'json',
		action: 'query',
		prop: 'revisions',
		rvprop: 'content',
		rvlimit: 1,
		titles: 'Wikipedia:Sandbox'
	}
)
	.then(function ( data ) {
		var page, wikitext;
		try {
			for ( page in data.query.pages ) {
				wikitext = data.query.pages[page].revisions[0]['*'];
				doSomethingWithText( wikitext );
			}
		} catch ( e ) {
			doSomethingInCaseOfError();
		}
	})
	.catch( doSomethingInCaseOfError );

Edit a page and other common actions[edit]

Scripts can perform common actions (like editing, protection, blocking, deletion, etc.) through the API. These actions require an edit token, which is valid for any action during the same session. (However, you should get a new token for different tasks in case this changes in the future.)

The code below shows how to edit a page, but it can easily be adapted to other actions by reading the API documentation.

Using module mediawiki.api[edit]

Note: make sure to add «mediawiki.api» to your dependencies!

// Edit page via the mw.Api module.
// postWithEditToken( {} ) may be used instead of postWithToken("csrf", {} )
// for actions such as editing that require a CSRF token.
// The line "text: info.text," will cause the call 
// to replace entire page content with supplied data.
// alternatively, one can append or prepend the data to the page, by using
// "appendtext: info.text," or "prependtext: info.text," instead.
// when using "appendtext", it is possible to append the text to a specific section,
// by setting the optional field "section".
function editPage( info ) {
	var api = new mw.Api();
	api.postWithToken("csrf", {
		action: 'edit',
		title: info.title,
		text: info.text, // will replace entire page content
		summary: info.summary
	} ).done(function( data ) {
		alert( 'Page edited!' );
	} ).fail( function(code, data) {
		console.log( api.getErrorMessage( data ).text());
	} );
}
editPage({
	title: 'User:' + mw.config.get( 'wgUserName' ) + '/Sandbox',
	text: 'Cool! It works! :-) ~~' + '~~',
	summary: 'Trying to edit my sandbox [[Project:User scripts/Guide|using API]]...'
});
Using plain jQuery[edit]
// Edit page (must be done through POST)
// the line "text: info.text," will cause the call 
// to replace entire page content with supplied data.
// alternatively, one can append or prepend the data to the page, by using
// "appendtext: info.text," or "prependtext: info.text," instead.
// when using "appendtext", it is possible to append the text to a specific section,
// by setting the optional field "section".
function editPage( info ) {
	$.ajax({
		url: mw.util.wikiScript( 'api' ),
		type: 'POST',
		dataType: 'json',
		data: {
			format: 'json',
			action: 'edit',
			title: info.title,
			text: info.text, // will replace entire page content
			summary: info.summary,
			token: mw.user.tokens.get( 'csrfToken' )
		}
	})
	.then (function( data ) {
		if ( data && data.edit && data.edit.result && data.edit.result == 'Success' ) {
			alert( 'Page edited!' );
		} else {
			alert( 'The edit query returned an error. =(' );
		}
	})
	.catch ( function() {
		alert( 'The ajax request failed.' );
	});
}
editPage({
	title: 'User:' + mw.config.get( 'wgUserName' ) + '/Sandbox',
	text: 'Cool! It works! :-) ~~' + '~~',
	summary: 'Trying to edit my sandbox [[Project:User scripts/Guide/Ajax|using AJAX]]...'
});

Load JavaScript from Wiki page[edit]

Security warning: Do not load Wikipedia pages that do not end in .js into your script using this method, because anybody can edit those pages.

let title = "User:YourName/YourScript.js";
mw.loader.load( "https://en.wikipedia.org/w/index.php?title="+title+"&action=raw&ctype=text/javascript" );

Load JSON from Wiki page[edit]

JSON is useful when you want to import complex data into your script. For example, maybe you have a bot that publishes certain data to a Wiki page regularly, and you want your script to read that data.

Careful with ctype. Set it to raw for normal Wiki pages, and application/json for pages where a template editor or admin has set the Content Model to JSON.

let jsonData;
let title = "User:YourName/YourData.json";
$.getJSON(mw.config.get('wgScriptPath')+'/index.php?action=raw&ctype=application/json&title='+title, function(data){
	jsonData = data;
}),

Working with CSS[edit]

Some user scripts also use some CSS code, or even are built with CSS only. Then you need to code and test CSS code. That can be done in your /common.css, but it is slow and messy.

Instead, you can load a CSS file from your local web server (see the previous section for an easy-to-install web server). Put this line at the very top of your /common.css:

@import "http://localhost/wikipediatest.css";

Note! Such @import statements must come before any other declarations in your CSS. But there can be /* comments */ above them.

An alternative way is to put this line in your Javascript file instead:

mw.loader.load( 'http://localhost/wikipediatest.css', 'text/css' );

Publishing a CSS file[edit]

Once you have finished the CSS code, you either need to paste it into your /vector.css if it is only for personal use. Or if it is for use by others then you should upload it to for instance User:Yourname/yourscript.css. Then other users can import it by putting the following line in their /common.js file. Note, that is in their «.js», not their «.css».

importStylesheet( 'User:Yourname/yourscript.css' );

If the CSS should be used together with a user script written in JavaScript then you can make it easy for the users. Simply put the line above in the JavaScript code for your user script, then the users only need to «install» your JavaScript.

For completeness, in case someone wonders, users can import your User:Yourname/yourscript.css from their /common.css too. This of course has the advantage that it works even if the user has JavaScript disabled. Although it takes this slightly complex line of code:

@import "/w/index.php?title=User:Yourname/yourscript.css&action=raw&ctype=text/css";

See also[edit]

  • Wikipedia:User scripts/Techniques
  • mw:ResourceLoader/JavaScript Deprecations#ajax.js
  • mw:ResourceLoader/Default modules#jQuery & plugins

Notes[edit]

  1. ^ a b The actual requirement is that the page have contentmodel «javascript». Making a page whose title ends in «.js» will automatically give it that content model and indicates to readers that the page contains JavaScript.
  2. ^ Firebug is strongly recommended for convenient debugging.
  3. ^ Dragonfly is strongly recommended for convenient debugging.
  4. ^ See mw:Extension:WikiEditor/Toolbar customization for information on how to customize WikiEditor.
  5. ^ See User:V111P/js/addToolbarButtons for a script which allows you to easily add buttons to whichever of the two toolbars the user is using.

References[edit]

  1. ^ This section originally written by raylu my monobook.js
    Thanks a ton to all the users who helped improve this tutorial!
  2. ^ https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content
  3. ^ https://lists.wikimedia.org/pipermail/mediawiki-l/2010-June/034396.html

Понравилась статья? Поделить с друзьями:
  • Как написать полчаса слитно или раздельно
  • Как написать полтора миллиона цифрами правильно
  • Как написать полтора метра цифрами
  • Как написать полтора месяца
  • Как написать полстакана правильно