Tarkibga o'tish

Aliaslar va muhit o'zgaruvchilari

Aliaslar terminalda yoziladigan buyruqlarni qisqartiradi. Muhit o'zgaruvchilari esa dasturlarga nomlangan qiymatlarni uzatadi. Ikkalasi ham shell bilan ishlashni qulaylashtiradi, lekin ular butunlay boshqacha ishlaydi. Aliasni buyruq ishga tushishidan oldin joriy interaktiv shell’ning o'zi almashtiradi. Muhit o'zgaruvchisi esa shell yangi dastur ishga tushirganda o'sha bola jarayonga meros bo'lib o'tadi.

Maqoladagi misollar Ubuntu Server LTS’dagi Bash uchun yozilgan. U Buyruq sintaksisi va yordam hujjatlari maqolasining davomi, ayniqsa qo'shtirnoqlar, type va PATH mavzulariga tayanadi.

Alias, shell o'zgaruvchisi va muhit o'zgaruvchisi

Tushuncha Kim ishlatadi Bola jarayonlarga o'tadimi? Misol
Alias Joriy interaktiv Bash buyruq qatori Yo'q alias ll='ls -lah'
Shell o'zgaruvchisi Joriy shell Faqat export qilinsa project='demo api'
Muhit o'zgaruvchisi Shell va uning bola jarayonlari Ha export EDITOR='nano'

Export qilingan o'zgaruvchi ota shell’da baribir oddiy shell o'zgaruvchisi bo'lib qoladi. Farqi shundaki, Bash uni keyin ishga tushadigan bola jarayonlar muhitiga nusxalanadigan qilib belgilab qo'yadi. Bola jarayon qiymatning nusxasini oladi. Ishga tushib bo'lgach, u ota shell’ning muhitini o'zgartira olmaydi.

Aliaslar bilan ishlash

Mavjud aliaslarni ko'rish:

alias
alias ll 2>/dev/null

Ubuntu’ning standart interaktiv Bash sozlamalarida ll aliasi bo'lishi mumkin, minimal o'rnatilgan serverda esa bo'lmasligi mumkin.

Alias yaratish:

alias ll='ls -lah'
alias c='clear'
type ll

Kutiladigan natija:

ll is aliased to `ls -lah'

= belgisining ikki tomonida bo'sh joy bo'lmasligi kerak. Shell alias qiymatini yaratish paytida bitta qiymat sifatida saqlashi uchun uni qo'shtirnoqqa oling.

Alias to'laqonli parametrlar tizimi emas. U buyruqning doim bir xil boshlanadigan qismini qisqartirish uchun yaxshi ishlaydi:

alias grep='grep --color=auto'

Lekin argumentni buyruqning o'rtasiga qo'yish kerak bo'lsa, alias to'g'ri vosita emas. Buning uchun funksiyadan foydalaning:

mkcd() {
    mkdir -p -- "$1" && cd -- "$1"
}

Bu misol laboratoriya uchun qulay. Production’da ishlatiladigan funksiya esa argument berilmagan holatni va xatolarni alohida tekshirishi kerak.

Aliasni chetlab o'tish yoki o'chirish

Bitta nom nimalarni anglatishi mumkinligini to'liq ko'rish:

type -a ls

Aliasni chetlab o'tish:

command ls
\ls

command ls aliaslar bilan birga shell funksiyalarini ham chetlab o'tadi va buyruqni odatdagidek ichki buyruqlar yoki PATH orqali qidiradi. So'z boshidagi teskari chiziq (\) esa faqat shu so'z uchun alias almashtirilishining oldini oladi.

Bitta aliasni o'chirish:

unalias c

Joriy shell’dagi barcha aliaslarni ataylab tozalamoqchi bo'lmasangiz, unalias -a ni ishlatmang.

Shell o'zgaruvchilari

Shell o'zgaruvchisini yaratish:

project='demo api'
echo "$project"

Natija:

demo api

Qiymat berish sintaksisi qat’iy:

project='demo'

Bu qiymat berish. Lekin quyidagisi:

project = demo

project nomli buyruq sifatida tushuniladi, = va demo esa uning argumentlari bo'lib qoladi.

O'zgaruvchi nomlarida katta-kichik harf farqlanadi. Odatda muhitga uzatiladigan o'zgaruvchilar katta harflar bilan, skript ichidagi mahalliy shell o'zgaruvchilari esa ko'pincha kichik harflar bilan yoziladi.

Muhitga export qilish

Export qilinmagan shell o'zgaruvchisi bola jarayonga o'tmaydi:

project='demo api'
bash -c 'echo "child sees: <$project>"'

Natija:

child sees: <>

Uni export qiling:

export project
bash -c 'echo "child sees: <$project>"'

Natija:

child sees: <demo api>

Yaratish va export qilishni bitta qadamda bajarish:

export EDITOR='nano'

O'zgaruvchilarni tekshirish:

printenv EDITOR
echo "$EDITOR"
declare -p EDITOR

Bu buyruqlar biroz boshqa-boshqa savollarga javob beradi:

  • printenv EDITOR qiymatni jarayon muhitidan olib chiqaradi.
  • echo "$EDITOR" Bash shell o'zgaruvchisini almashtirgandan keyingi qiymatni chiqaradi.
  • declare -p EDITOR faqat Bash’da bor va o'zgaruvchining atributlarini, jumladan u export qilingan-qilinmaganini ko'rsatadi.

O'zgaruvchini joriy shell’dan o'chirish:

unset project

Bu buyruq allaqachon ishga tushib bo'lgan jarayonlarga ta’sir qilmaydi.

Muhitning meros bo'lib o'tishi

Yangi dastur ishga tushganda muhit ota jarayondan bola jarayonga nusxalanadi:

Bash with APP_MODE=staging exported
  -> python app.py receives APP_MODE=staging
  -> bash receives APP_MODE=staging
       -> env prints that child's environment

Bola jarayon o'z nusxasini o'zgartirishi mumkin, lekin bu ota jarayonga ta’sir qilmaydi:

export APP_MODE='staging'
bash -c 'APP_MODE=testing; echo "child=$APP_MODE"'
echo "parent=$APP_MODE"

Natija:

child=testing
parent=staging

O'zgaruvchini faqat bitta buyruq uchun berish:

LC_ALL=C sort names.txt

Bu LC_ALL ni faqat shu sort jarayoni va uning bola jarayonlari uchun o'rnatadi. Buyruq tugagach, joriy shell’da bu qiymat bo'lmaydi.

Ko'p uchraydigan muhit o'zgaruvchilari

Ulardan bir nechtasini ko'rib chiqing:

printenv HOME USER SHELL PATH LANG

Muhim o'zgaruvchilar:

  • HOME: foydalanuvchining uy katalogi.
  • USER yoki LOGNAME: tizimga kirgan foydalanuvchi nomi (qaysi biri ishlatilishi dasturga bog'liq).
  • SHELL: foydalanuvchi uchun sozlangan login shell. U hozir ishlab turgan shell’ni aniq ko'rsatmaydi.
  • PATH: buyruqlar qidiriladigan kataloglar ro'yxati.
  • LANG va LC_*: til, saralash va formatlash uchun locale sozlamalari.
  • TZ: ba’zi dasturlar o'z jarayoni uchun ishlatadigan vaqt zonasi.
  • EDITOR va VISUAL: bu o'zgaruvchilarni hisobga oladigan dasturlar uchun afzal ko'rilgan matn muharriri.

Hozir ishlab turgan shell’ni alohida tekshiring:

echo "$BASH_VERSION"
ps -p $$ -o comm=

EDITOR va VISUAL

Ba’zi vositalar muharrirni VISUAL yoki EDITOR qiymatiga qarab ochadi:

export EDITOR='nano'
export VISUAL="$EDITOR"

Hamma dasturlar ham bu o'zgaruvchilarni hisobga olavermaydi. Buni dasturning qo'llanma sahifasidagi ENVIRONMENT bo'limidan tekshiring.

TZ, LANG va takrorlanadigan natija

Vaqt natijalarini solishtiring:

TZ=UTC date
date

Birinchi buyruq UTC vaqtini faqat o'sha jarayon uchun ishlatadi. Tizimning vaqt zonasi o'zgarmaydi.

Locale saralash tartibini va xabarlar tilini o'zgartirishi mumkin. Shu sabab baytma-bayt va har safar bir xil natija beradigan saralash kerak bo'lgan skriptlarda ko'pincha quyidagicha yoziladi:

LC_ALL=C sort names.txt

PATH: buyruqlarni qidirish yo'li

PATH ni chiqarish:

echo "$PATH"

Bu ikki nuqta (:) bilan ajratilgan kataloglar ro'yxati. Buyruq nomida / bo'lmasa, Bash bajariladigan faylni shu kataloglardan chapdan o'ngga qarab qidiradi.

Qaysi dastur ishga tushishini aniqlash:

command -v ls
type -a ls

Mavjud yo'lni yo'qotmasdan shaxsiy bin katalogini qo'shish:

mkdir -p "$HOME/.local/bin"
export PATH="$HOME/.local/bin:$PATH"

Tekshirish:

case ":$PATH:" in
    *":$HOME/.local/bin:"*) echo "present" ;;
    *) echo "missing" ;;
esac

Warning

export PATH="$HOME/.local/bin" deb yozib, PATH ni bilmasdan almashtirib yubormang. Bunda tizim kataloglari ro'yxatdan chiqib ketadi va oddiy buyruqlar ham ishlamay qolishi mumkin. PATH ga . ni yoki hamma yoza oladigan kataloglarni qo'shmang, ayniqsa root uchun.

Agar Bash buyruqlar joylashuvini eslab qolgan bo'lsa va siz PATH ni o'zgartirgan bo'lsangiz, bu xotirani (hash jadvalini) tozalang:

hash -r

Sozlamalarni doimiy saqlash

Terminalda yozilgan aliaslar va o'zgaruvchilar shell yopilishi bilan yo'qoladi. Ularni saqlab qolish uchun to'g'ri ishga tushish (startup) fayliga yozing.

Debian va Ubuntu’dagi Bash uchun:

  • Interaktiv, lekin login bo'lmagan shell’lar odatda /etc/bash.bashrc va ~/.bashrc ni o'qiydi.
  • Interaktiv login shell’lar avval /etc/profile ni, keyin ~/.bash_profile, ~/.bash_login va ~/.profile dan birinchi o'qish mumkin bo'lganini o'qiydi.
  • Ubuntu’ning standart ~/.profile fayli Bash uchun ~/.bashrc ni chaqirishi mumkin, lekin buni taxmin qilmasdan, faylning o'zini tekshiring.
  • Nointeraktiv shell’lar, cron vazifalari va systemd xizmatlari o'z-o'zidan sizning terminalingiz kabi ishlamaydi.

~/.bashrc ga aliasni xavfsiz qo'shish:

cp -a ~/.bashrc ~/.bashrc.before-alias
nano ~/.bashrc
bash -n ~/.bashrc

Quyidagi qatorni boshqa aliaslar yoniga qo'shing:

alias ll='ls -lah'

bash -n faylni bajarmasdan, faqat sintaksisini tekshiradi. Yangi shell’da sinab ko'ring:

bash
type ll
exit

O'zgargan faylni joriy shell’ga quyidagicha yuklashingiz mumkin:

. ~/.bashrc

Faqat o'zingiz ishongan fayllarni shu tarzda yuklang (source qiling). Bunda fayldagi shell kodi joriy shell’ingiz ichida bajariladi.

Xizmatlar ishlatadigan muhit o'zgaruvchilari uchun ~/.bashrc ga tayanmang. Buning uchun xizmat menejerining o'z usulidan foydalaning, masalan systemd unit faylidagi Environment= qatori yoki EnvironmentFile=. Bu mavzu keyingi darslarda ko'rib chiqiladi.

Xavfsizlik va production bo'yicha eslatmalar

  • Muhit o'zgaruvchilarini jarayonning o'zi, ko'pincha esa shu foydalanuvchi yoki root ishga tushirgan diagnostika vositalari ham ko'ra oladi. Ularni maxfiy ma’lumotlar ombori deb hisoblamang.
  • LD_PRELOAD, LD_LIBRARY_PATH, PYTHONPATH va shunga o'xshash o'zgaruvchilar bilan ehtiyot bo'ling. Ular dastur qaysi kodni yuklashini o'zgartirib yuborishi mumkin.
  • sudo odatda siyosatga ko'ra muhit o'zgaruvchilarini tozalaydi yoki filtrlaydi. Huquqni oshirganingizda shell muhitingiz o'zgarmasdan saqlanib qoladi deb o'ylamang.
  • Umumiy serverlarda aliaslarni kam va oddiy saqlang. Ish uslubingiz ko'plab shaxsiy aliaslarga bog'liq bo'lsa, toza tizimda xato qilib qo'yishingiz mumkin.
  • Skriptlarda buyruqlarni to'liq yozing. Aliaslar asosan terminalda qo'lda ishlash uchun.

LD_PRELOAD nima uchun muhim?

LD_PRELOAD — Bash emas, dinamik bog'lovchi (dynamic linker) o'qiydigan muhit o'zgaruvchisi. Dinamik bog'langan dastur ishga tushganda bog'lovchi LD_PRELOAD da ko'rsatilgan har bir umumiy kutubxonani (shared library) dasturning odatdagi kutubxonalaridan oldin yuklaydi. Natijada shu kutubxonadagi funksiyalar dastur odatda chaqiradigan bir xil nomli funksiyalardan ustun bo'ladi. Bu qonuniy diagnostika usuli: profilerlar va libasan kabi xotira tekshiruvchilari tekshirilayotgan dasturni qayta kompilyatsiya qilmasdan unga shu yo'l bilan ulanadi.

Aynan shu mexanizm uni production uchun xavfli qiladi. LD_PRELOAD orqali ulangan zararli yoki buzilgan kutubxona libc’ning keng tarqalgan funksiyalarini — read, open, getuid, parol tekshiruvida ishlatiladigan funksiyalarni — almashtirib qo'yishi mumkin. Shunda dastur nimani ko'rishi yoki nima qilishi o'zgaradi, dasturning o'zi esa buni sezmaydi:

printf '%s\n' 'int getuid(void) { return 0; }' > /tmp/fake.c
gcc -shared -fPIC -o /tmp/fake.so /tmp/fake.c
LD_PRELOAD=/tmp/fake.so id -u
0

id -u odatda foydalanuvchining haqiqiy raqamli ID sini ko'rsatadi. Bu yerda esa root bo'lmagan foydalanuvchi uchun 0 chiqdi, chunki LD_PRELOAD dastur kim ishga tushirganini aniqlash uchun tayanadigan getuid chaqiruvini almashtirib qo'ydi. Hech qanday fayl ruxsati chetlab o'tilmadi va hech qanday ekspluatatsiya kerak bo'lmadi: dastur ishga tushishidan oldinroq uning libc chaqiruvlari jimgina boshqa joyga yo'naltirildi. Shu sababli sudo va huquqlarni hisobga oladigan boshqa vositalar biror narsani bajarishdan oldin LD_PRELOAD va shunga o'xshash o'zgaruvchilarni muhitdan olib tashlaydi. Meros bo'lib kelgan LD_PRELOAD yuqori huquq bilan birlashsa, diagnostika imkoniyati imtiyozli jarayonning tizimni qanday ko'rishini egallab olish vositasiga aylanadi. Yuqori huquq bilan ishlaydigan hech narsa uchun LD_PRELOAD yoki LD_LIBRARY_PATH ni o'rnatmang va ularni ishonchsiz muhitdan qabul qilmang. Xizmat muhitida sababi noma’lum LD_PRELOAD topilsa, uni g'alati sozlama deb emas, tekshirilishi kerak bo'lgan xavfsizlik hodisasi deb qabul qiling.

Amaliy vaziyat: skript terminalda ishlaydi, cron’da esa ishlamaydi

Muammo: texnik xizmat skripti SSH orqali qo'lda ishga tushirilganda muammosiz ishlaydi, lekin xuddi shu skript cron orqali rejalashtirilganda xato beradi yoki boshqacha ishlaydi.

Taxmin qilish o'rniga cron muhitini qayta hosil qilib ko'ring:

crontab -l
*/5 * * * * /home/admin/bin/cleanup.sh >> /home/admin/cleanup.log 2>&1

Cron bu qatorni /bin/sh orqali (bu sizning login Bash ingiz bo'lishi shart emas) interaktiv bo'lmagan va login bo'lmagan shell’da bajaradi. Shell va Bash qanday ishlaydi maqolasida aytilganidek, bunday shell ~/.bashrc ni o'qimaydi. Farqni ikkala muhitni faylga yozib, solishtirish orqali tasdiqlang:

env > /home/admin/env-interactive.txt

O'z muhitini faylga yozadigan bir martalik cron vazifasini qo'shing, u ishga tushishini kuting, so'ng solishtiring:

* * * * * /usr/bin/env > /home/admin/env-cron.txt
diff /home/admin/env-interactive.txt /home/admin/env-cron.txt

Odatda natijada cron’dagi PATH ancha qisqa ekani ko'rinadi. Skriptingiz bilinmay tayangan aliaslar yoki ~/.bashrc da export qilingan o'zgaruvchilar esa umuman yo'q bo'ladi:

< PATH=/home/admin/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
---
> PATH=/usr/bin:/bin
< APP_MODE=staging

Xulosa: bu muammoni ~/.bashrc dagi sozlamalarni cron’ga ko'chirish bilan hal qilmang. Skriptning o'zini tuzating: u ishlatadigan har bir buyruq va fayl uchun to'liq yo'lni yozing, kerakli o'zgaruvchilarni skript boshida yoki crontab’ning o'zidagi muhit qatorlarida (jadval qatoridan yuqorida PATH=... va VAR=value) aniq belgilang. Cron vazifasidagi shell sizning terminalingiz o'qiydigan fayllarni o'qiydi deb hisoblamang. Solishtirib bo'lgach, bir martalik tekshiruv qatorini crontab’dan olib tashlang.

Amaliy vaziyat: qulay va xavfsiz ro'yxat buyrug'i

Muammo: o'z terminalingizda qulay ll buyrug'i bo'lishini xohlaysiz, lekin skriptlar yoki boshqa foydalanuvchilar unga bog'lanib qolishini istamaysiz.

Uni joriy shell uchun yarating:

alias ll='ls -lah'
type ll
ll ~/lab

Zaxira nusxa olib, uni ~/.bashrc ga doimiy yozing:

cp -a ~/.bashrc ~/.bashrc.before-ll
nano ~/.bashrc
bash -n ~/.bashrc

Yangi, toza interaktiv Bash oching:

bash
type ll
exit

Xulosa: alias faqat terminalda ishlash uchun qulaylik. Boshqa serverlar uchun hujjat, skript yoki runbook yozayotganda buyruqni to'liq yozing:

ls -lah /some/path

Keng tarqalgan xatolar

  • Qiymat berishda = atrofiga bo'sh joy qo'yish.
  • Aliaslar skriptlarda ham ishlaydi deb kutish.
  • Bo'sh joyi bor qiymatlarni qo'shtirnoqqa olmaslik.
  • $SHELL ni hozirgi jarayon qaysi shell ekanining isboti deb hisoblash.
  • PATH ga qo'shish o'rniga uni butunlay qayta yozib yuborish.
  • Oqibatlarini tushunmasdan maxfiy ma’lumotlarni muhit o'zgaruvchilarida saqlash.
  • ~/.bashrc ni zaxira nusxasiz va sintaksis tekshiruvisiz tahrirlash.

Mashqlar

  1. lh='ls -lh' aliasini yarating, uni type bilan tekshiring, so'ng unalias bilan o'chiring.
  2. Qiymatida bo'sh joy bor shell o'zgaruvchisini yarating. Uni export qilmaguningizcha bola Bash jarayoni ko'ra olmasligini isbotlang.
  3. date ni vaqtincha TZ=UTC bilan ishga tushiring, so'ng ota shell’dagi TZ o'zgarmaganini isbotlang.
  4. Joriy shell’da $HOME/.local/bin ni PATH ga qo'shing va asl PATH ni yo'qotmasdan, uning ro'yxatdagi o'rnini tekshiring.

Mashqni bajardim deyish uchun: biror sozlama faqat joriy buyruq qatoriga, joriy shell’ga, bola jarayonlarga yoki keyingi login sessiyalarga ta’sir qilishini tushuntirib bera olishingiz kerak.

Manbalar

  • Bash qo'llanma sahifasi: https://man7.org/linux/man-pages/man1/bash.1.html
  • GNU Bash Reference Manual: https://www.gnu.org/software/bash/manual/bash.html
  • environ(7) Linux qo'llanma sahifasi: https://man7.org/linux/man-pages/man7/environ.7.html
  • execve(2) Linux qo'llanma sahifasi: https://man7.org/linux/man-pages/man2/execve.2.html
  • GNU Coreutils printenv: https://www.gnu.org/software/coreutils/manual/html_node/printenv-invocation.html
  • ld.so(8) Linux qo'llanma sahifasi (LD_PRELOAD, LD_LIBRARY_PATH): https://man7.org/linux/man-pages/man8/ld.so.8.html
  • crontab(5) Linux qo'llanma sahifasi: https://man7.org/linux/man-pages/man5/crontab.5.html