Shell va Bash qanday ishlaydi
Terminal oynasi Linux buyruqlarini o'zi bajarmaydi. U sizga matnli interfeys taqdim etadi, kiritgan ma’lumotlaringizni shell’ga yuboradi va qaytib kelgan natijani ekranda ko'rsatadi.
Shell
Shell — buyruq qatorini o'qiydigan, o'z qoidalarini qo'llaydigan hamda ichki amalni bajaradigan yoki boshqa dasturni ishga tushiradigan dastur.
Ubuntu Serverda buyruqlarni qabul qilib, bajarishga tayyorlaydigan dastur shell deb ataladi. Ubuntu Serverda shell sifatida ko'pincha Bash ishlatiladi.
Terminalga yozgan har bir buyruq avval Bash tomonidan tekshiriladi va tayyorlanadi, keyin kerakli dastur ishga
tushiriladi. Masalan, ls *.log deb yozsangiz, Bash avval *.log o'rniga .log bilan tugaydigan fayllar nomini
qo'yadi. Shundan keyingina ls buyrug'ini ishga tushiradi.
Ba’zi buyruqlar esa alohida dastur emas, Bashning o'ziga tegishli buyruqlardir. Masalan, cd shunday buyruq. Shu
sababli tizimda /usr/bin/cd nomli dastur bo'lmasa ham, cd ishlaydi va joriy katalogni o'zgartiradi.
Ushbu bo'limdagi misollar Ubuntu Server LTS va Bash muhiti uchun berilgan. Buyruqlar boshidagi $ belgisi yozilmaydi.
U faqat terminal buyruq kiritishga tayyorligini ko'rsatadi.
Terminal, shell, dastur va yadro
Terminalda buyruq yozganimizda bir nechta qatlam birgalikda ishlaydi. Ularning har biri alohida vazifani bajaradi:
- Terminal emulyatori — buyruqlarni klaviatura orqali kiritish va natijani ekranda ko'rish uchun ishlatiladigan dastur.
- GNOME Terminal va Windows Terminal terminal emulyatorlariga misol bo'ladi. SSH klienti esa masofadagi server terminaliga ulanish imkonini beradi.
- Shell — foydalanuvchi yozgan buyruqlarni qabul qiladigan, tushunadigan va bajarishga tayyorlaydigan dastur. Bash, Zsh, Fish va Dash shell turlaridir.
- Dastur — ma’lum bir vazifani bajaradigan kod. Masalan,
/usr/bin/lsfayllar ro'yxatini chiqaradigan tashqi dasturdir.cdesa alohida dastur emas, Bash ichida mavjud bo'lgan buyruqdir. - Yadro — Linux tizimining asosiy qismi. U jarayonlar, tezkor xotira, fayl tizimlari, qurilmalar, tarmoq va ruxsatlarni boshqaradi.
Terminalga buyruq yozganingizdan boshlab, amal bajarilguncha jarayon taxminan quyidagi tartibda davom etadi:
foydalanuvchi
-> terminal yoki SSH klienti
-> Bash
-> Bash ichki buyrug'i yoki tashqi dastur
-> Linux yadrosi
-> fayllar, qurilmalar, jarayonlar yoki tarmoq
Masalan, quyidagi buyruqni ko'rib chiqamiz:
Bu buyruq bajarilganda quyidagilar sodir bo'ladi:
- Bash
catnomli dasturni qidiradi. /etc/hostnameqiymatinicatdasturiga argument sifatida beradi.- Bash
catdasturini yangi jarayon sifatida ishga tushiradi. catfaylni o'qish uchun Linux yadrosiga murojaat qiladi.- Yadro fayldagi ma’lumotni
catdasturiga beradi. catnatijani terminalga chiqaradi.
Endi quyidagi buyruqni ko'rib chiqamiz:
cd alohida tashqi dastur emas. U Bash ichida mavjud bo'lgan ichki buyruqdir.
cd buyrug'i ayni vaqtda ishlayotgan Bashning joriy katalogini o'zgartirishi kerak. Shu sababli u alohida dastur
sifatida emas, Bashning ichki buyrug'i sifatida ishlaydi.
Agar cd alohida dastur bo'lganida, u vaqtincha yangi jarayonda ishga tushardi. Bu jarayon faqat o'z katalogini
o'zgartira olardi. Jarayon yopilgach, asosiy Bash avvalgi katalogida qolaverardi.
Shuning uchun cd bevosita Bash ichida bajariladi va foydalanuvchi turgan joriy katalogni o'zgartiradi.
Joriy shell’ni aniqlash
Terminaldagi prompt ko'rinishiga qarab qaysi shell ishlayotganini aniq bilib bo'lmaydi. Chunki promptni istalgan ko'rinishga sozlash mumkin.
Joriy muhit haqida ma’lumot olish uchun quyidagi buyruqlardan foydalaning:
Odatdagi natija quyidagicha bo'lishi mumkin:
Har bir qatorning ma’nosi:
$SHELLfoydalanuvchi hisobi uchun tanlangan login shell’ni ko'rsatadi. Masalan,/bin/bash.- Lekin
$SHELLayni vaqtda ishlayotgan shell’ni har doim ham aniq ko'rsatmaydi. Masalan, Bash ichidan vaqtincha Zsh ishga tushirilsa ham,$SHELLeski qiymatda qolishi mumkin. $BASH_VERSIONfaqat joriy shell Bash bo'lsa qiymatga ega bo'ladi. U Bash versiyasini ko'rsatadi.$$joriy shell jarayonining PID raqamini bildiradi.ps -p $$aynan shu PID bilan ishlayotgan jarayon haqida ma’lumot chiqaradi.- Natijadagi
-bashyozuvi Bash login shell sifatida ishga tushirilganini bildiradi.
Tizimda login shell sifatida ishlatishga ruxsat berilgan shell’lar odatda quyidagi faylda yoziladi:
Bu fayl tizimdagi barcha shell dasturlarini ko'rsatishi shart emas. U faqat login qilish uchun yaroqli deb hisoblangan shell’lar ro'yxatini saqlaydi.
Promptni o'qish
Terminal prompti ko'pincha quyidagicha ko'rinadi:
Bu qismlar odatda quyidagi ma’noni anglatadi:
admin— joriy foydalanuvchi nomi.web01— kompyuter yoki server nomi.~/project— joriy ish katalogi.~— foydalanuvchining uy katalogi. Masalan,adminfoydalanuvchisi uchun u odatda/home/adminkatalogini bildiradi.$— odatda oddiy foydalanuvchi ishlayotganini bildiradigan prompt belgisi.
Root foydalanuvchisining prompti ko'pincha # belgisi bilan tugaydi. Lekin bu faqat odatiy ko'rinish. Promptni o'zgartirish mumkin, shuning uchun faqat $ yoki # belgisiga ishonmang.
Joriy foydalanuvchi va huquqlarni quyidagi buyruqlar yordamida tekshiring:
Bu buyruqlarning vazifasi:
id— foydalanuvchi UID raqami, asosiy guruhi va boshqa guruhlarini ko'rsatadi.id -u— faqat joriy foydalanuvchining UID raqamini chiqaradi.whoami— joriy foydalanuvchi nomini ko'rsatadi.pwd— ayni vaqtda qaysi katalogda turganingizni ko'rsatadi.
Agar id -u buyrug'i 0 chiqarsa, siz root huquqi bilan ishlayapsiz. Bu ma’lumot promptdagi belgidan ko'ra ishonchliroq.
Warning
Root — UID raqami 0 bo'lgan, tizimda deyarli barcha amallarni bajarish huquqiga ega superfoydalanuvchi.
Linux fayl tizimining eng yuqori / katalogi ham root katalog deb ataladi. Lekin root foydalanuvchi va root katalog ikki xil tushunchadir.
Kundalik ishlarni doimiy ravishda root shell ichida bajarmang. Ma’muriy huquq talab qiladigan aniq buyruqlardagina sudo ishlating.
Ichki buyruqlar, aliaslar, funksiyalar va tashqi buyruqlar
Terminalga yozilgan buyruq nomi har doim ham diskdagi bitta dastur faylini anglatmaydi.
Masalan, ls quyidagilardan biri bo'lishi mumkin:
- Bash ichki buyrug'i;
- alias;
- shell funksiyasi;
- diskdagi tashqi dastur.
Buyruq nomi nimani anglatishini tekshirish uchun quyidagi buyruqlardan foydalaning:
Mumkin bo'lgan natija:
cd is a shell builtin
echo is a shell builtin
pwd is a shell builtin
pwd is /usr/bin/pwd
ls is aliased to `ls --color=auto'
ls is /usr/bin/ls
Bu natijani quyidagicha o'qish mumkin:
cd— Bashning ichki buyrug'i.echo— Bashning ichki buyrug'i.pwd— Bash ichida ham mavjud./usr/bin/pwdnomli tashqi dastur ham mavjud.lsuchunls --color=autoaliasi yaratilgan.- Asl tashqi
lsdasturi/usr/bin/lsmanzilida joylashgan.
Demak, “buyruq” deganda har doim bitta bajariladigan fayl nazarda tutilmaydi.
Bash buyruqni bajarishdan oldin uning:
- alias ekanini;
- funksiya ekanini;
- ichki buyruq ekanini;
- yoki
PATHorqali topiladigan tashqi dastur ekanini aniqlaydi.
Bir xil buyruq ikki serverda turlicha ishlasa, darhol tizimda muammo bor deb o'ylamang. Avval buyruq manbasini tekshiring:
Masalan:
Bash ichki buyruqlari bo'yicha yordam olish uchun help ishlatiladi:
Tashqi GNU dasturlari odatda --help parametriga va man qo'llanma sahifasiga ega:
Keyingi maqola — Buyruq sintaksisi va yordam hujjatlari — yordam hujjatlaridagi sintaksisni qanday o'qishni tushuntiradi.
Dastur ishga tushishidan oldin Bash nima qiladi?
Terminalga buyruq yozib Enter tugmasini bosganingizda, Bash uni darhol tashqi dasturga yubormaydi.
Bash avval buyruq qatorini tahlil qiladi va kerakli o'zgartirishlarni bajaradi. Soddalashtirilgan tartib quyidagicha:
- Buyruq qatorini so'zlar va maxsus operatorlarga ajratadi.
- Alias mavjud bo'lsa, uni haqiqiy qiymatiga almashtiradi.
- O'zgaruvchilar,
$(...)buyruq almashtirishi, arifmetik ifodalar va~belgisini kengaytiradi. - Zarur joylarda matnni alohida argumentlarga ajratadi.
*.confkabi wildcard andozalarini mos fayl nomlariga almashtiradi.>,<va boshqa qayta yo'naltirishlarni tayyorlaydi.- Bash ichki buyrug'ini bajaradi yoki tashqi dasturni ishga tushiradi.
- Buyruqning natija kodini
$?o'zgaruvchisiga saqlaydi.
Wildcard kengayishini oddiy misolda ko'ramiz:
Kutiladigan natija:
Siz echo buyrug'iga faqat ~/lab/shell/*.conf deb yozdingiz. Lekin echo dasturi *.conf matnini olmadi.
Avval Bash shu andozaga mos fayllarni topdi:
Keyin Bash echo buyrug'ini taxminan quyidagi ko'rinishda bajardi:
Demak, wildcard kengayishini echo emas, Bash bajardi.
Agar andozaga mos fayl topilmasa, Bash odatda andozani o'z holicha qoldiradi. Masalan:
Mos fayl bo'lmasa, natija quyidagicha chiqishi mumkin:
Bu xatti-harakat nullglob kabi Bash sozlamalariga bog'liq. Shu sababli skript yozayotganda wildcard har doim kamida bitta fayl topadi, deb hisoblash xavfli.
IFS va so'zlarga ajratish
Bash ayrim qiymatlarni alohida so'zlarga ajratishda IFS nomli o'zgaruvchidan foydalanadi.
IFS — Internal Field Separator, ya’ni ichki maydon ajratgichi degani.
Standart holatda IFS quyidagi belgilarni ajratuvchi sifatida ishlatadi:
- bo'shliq;
- tabulyatsiya;
- yangi qator.
Masalan, o'zgaruvchida bo'shliq bo'lsa va u qo'shtirnoqsiz ishlatilsa, Bash uni bir nechta argumentga ajratishi mumkin.
Ba’zan ma’lumot boshqa belgi bilan ajratilgan bo'ladi. Masalan:
Bu qatorda qiymatlar : belgisi bilan ajratilgan. Uni qismlarga bo'lish uchun IFS qiymatini vaqtincha : qilib belgilash mumkin:
line='admin:1001:/home/admin'
IFS=':' read -r username uid home <<< "$line"
printf 'user=%s uid=%s home=%s\n' "$username" "$uid" "$home"
Natija:
Bu yerda:
usernameo'zgaruvchisigaadmin;uido'zgaruvchisiga1001;homeo'zgaruvchisiga/home/adminyozildi.
IFS qiymatini butun shell uchun o'zgartirib qo'yish ehtiyotkorlikni talab qiladi. Aks holda, keyingi buyruqlardagi matnlarning qanday ajratilishiga ham ta’sir qilishi mumkin.
Yuqoridagi misolda IFS=':' faqat read buyrug'i uchun qo'llanmoqda. Bu xavfsizroq usuldir.
Qo'shtirnoqlar argumentlarni o'zgartiradi
Quyidagi o'zgaruvchining qiymatida bo'shliq mavjud:
Endi uni qo'shtirnoq bilan va qo'shtirnoqsiz ishlatamiz:
Natija:
Birinchi buyruqda:
qiymat bitta argument sifatida uzatildi. Shuning uchun demo api bir qatorda chiqdi.
Ikkinchi buyruqda:
qiymat qo'shtirnoqsiz yozildi. Bash bo'shliq bo'yicha uni ikkita argumentga ajratdi:
Shuning uchun o'zgaruvchi qiymatini buyruqqa uzatishda odatda quyidagi shakl xavfsiz hisoblanadi:
Bir tirnoq va qo'shtirnoq farqi
Bir tirnoq va qo'shtirnoq Bashda bir xil vazifani bajarmaydi:
Natija:
Qo'shtirnoq ichida:
Bash o'zgaruvchini qiymatiga almashtiradi.
Bir tirnoq ichida:
Bash matnni o'zgartirmaydi. U $name yozuvini aynan o'z holicha chiqaradi.
Soddalashtirib aytganda:
"..."ichida o'zgaruvchilar ishlaydi;'...'ichidagi matn o'zgarmaydi.
Buyruq almashtirishi
Bir buyruq chiqargan natijani o'zgaruvchiga yozish uchun $(...) ishlatiladi:
Avval quyidagi buyruq bajariladi:
U Linux yadrosi versiyasini chiqaradi. Bash ushbu natijani kernel_release o'zgaruvchisiga yozadi.
Masalan, o'zgaruvchining qiymati quyidagicha bo'lishi mumkin:
Keyin:
taxminan quyidagi natijani chiqaradi:
Buyruq natijasini eval orqali qayta bajarmang. Ayniqsa, qiymat foydalanuvchi, tarmoq, fayl yoki boshqa ishonchsiz manbadan kelgan bo'lsa, bu xavfsizlik muammosiga olib kelishi mumkin.
eval nima uchun xavfli?
eval berilgan matnni oddiy ma’lumot sifatida emas, yangi Bash buyrug'i sifatida qayta o'qiydi va bajaradi.
Masalan:
filename o'zgaruvchisida quyidagi matn mavjud:
eval uni qayta tahlil qilgach, Bash quyidagi ikkita buyruqni ko'radi:
Natijada:
echo INJECTED alohida buyruq sifatida bajarildi.
Bu yerda oddiy ma’lumot Bash kodiga aylandi. Agar qiymatni hujumchi boshqarsa, u o'z buyrug'ini kiritishi mumkin.
Endi xuddi shu qiymatni eval ishlatmasdan tekshiramiz:
Natija:
cat: report.txt;: No such file or directory
cat: echo: No such file or directory
cat: INJECTED: No such file or directory
Bu safar Bash echo INJECTED ni yangi buyruq sifatida bajarmadi. cat shunchaki uchta fayl nomini ochishga urindi:
Fayllar mavjud bo'lmagani uchun xatolik chiqdi, lekin yangi buyruq ishga tushmadi.
Demak, xavfning asosiy sababi — eval ma’lumotni qayta Bash kodi sifatida talqin qilishidir.
Foydalanuvchi, tarmoq so'rovi, tashqi fayl yoki ishonchsiz konfiguratsiyadan kelgan qiymatlarni eval bilan ishlatmang.
Interaktiv, login va nointeraktiv shell’lar
Bash har doim bir xil usulda ishga tushmaydi. Uning qanday ishlashi qaysi turdagi shell sifatida ochilganiga bog'liq.
Interaktiv shell
Interaktiv shell foydalanuvchi bilan to'g'ridan-to'g'ri ishlaydi:
- prompt ko'rsatadi;
- klaviaturadan buyruq qabul qiladi;
- natijani terminalga chiqaradi.
Masalan, SSH orqali serverga kirib, buyruqlar yozayotganingizda odatda interaktiv shell ishlaydi.
Login shell
Login shell foydalanuvchi tizimga kirganida sessiyani boshlaydigan shell hisoblanadi.
U ishga tushganda login uchun mo'ljallangan sozlama fayllarini o'qiydi.
SSH orqali serverga odatiy kirishda Bash ko'pincha login shell sifatida ishlaydi.
Nointeraktiv shell
Nointeraktiv shell foydalanuvchidan buyruq kutmaydi va odatda prompt ko'rsatmaydi.
U quyidagi holatlarda ishlatiladi:
- Bash skripti bajarilganda;
bash -c 'buyruq'ishlatilganda;- ayrim cron yoki avtomatlashtirilgan vazifalarda.
Shell interaktiv ekanini tekshirish uchun:
Bu yerda $- joriy shell bayroqlarini saqlaydi. Agar uning ichida i harfi bo'lsa, shell interaktiv hisoblanadi.
Shell login shell ekanini tekshirish uchun:
Debian va Ubuntu tizimlarida Bash o'qiydigan sozlama fayllari shell turiga qarab farq qiladi.
Interaktiv, ammo login bo'lmagan Bash odatda quyidagi fayllarni o'qiydi:
Interaktiv login Bash odatda avval:
faylini o'qiydi. Keyin quyidagi fayllardan mavjud va o'qish mumkin bo'lgan birinchisini o'qiydi:
Nointeraktiv Bash esa standart holatda ~/.bashrc faylini o'qimaydi.
Bu production muhitida juda muhim.
Masalan, terminalda ishlayotgan buyruq quyidagi muhitlarda boshqacha ishlashi mumkin:
- SSH sessiyasida;
- cron ichida;
systemdservisida;- Docker konteynerida;
- Bash skriptida.
Buning sababi shundaki, bu muhitlarning har biri bir xil sozlama fayllarini o'qimasligi mumkin. Natijada terminalingizdagi aliaslar, PATH qiymati yoki boshqa muhit o'zgaruvchilari avtomatik ravishda mavjud bo'lmaydi.
Aliaslar va muhit o'zgaruvchilari maqolasida sozlamalarni turli jarayonlar uchun to'g'ri saqlash tushuntiriladi.
Chiqish holati
Har bir buyruq bajarilgandan keyin sonli natija kodi qaytaradi. Bu kod chiqish holati yoki exit status deb ataladi.
Shell va skriptlar shu kod orqali buyruq muvaffaqiyatli yoki xato bilan tugaganini biladi.
Misol:
Odatdagi natija:
drwxr-xr-x 160 root root 12288 Jul 29 12:00 /etc
status=0
ls: cannot access '/path/that/does/not/exist': No such file or directory
status=2
Birinchi ls buyrug'i mavjud /etc katalogini topdi. Shu sababli uning chiqish holati:
bo'ldi.
Ikkinchi ls buyrug'i mavjud bo'lmagan katalogni ochishga urindi. Shu sababli xatolik yuz berdi va chiqish holati:
bo'ldi.
Umumiy qoida:
0— buyruq muvaffaqiyatli bajarildi;0dan boshqa qiymat — buyruq boshqa holat yoki xatolik bilan tugadi.
Noldan boshqa har bir kod aynan bir xil ma’noni anglatmaydi. Masalan, 1, 2 yoki 127 kodlarining ma’nosi buyruqqa qarab farq qilishi mumkin. Aniq ma’noni buyruqning qo'llanmasidan tekshirish kerak.
Oxirgi bajarilgan buyruqning chiqish holati $? ichida saqlanadi.
Muhim jihat: $? har bir yangi buyruqdan keyin yangilanadi.
Masalan:
Bu yerda $? ls buyrug'ining holatini ko'rsatadi.
Agar qiymatni keyinroq ishlatmoqchi bo'lsangiz, uni darhol boshqa o'zgaruvchiga saqlang:
Bu usulda ls natija kodi status o'zgaruvchisida saqlanadi va keyingi buyruqlardan keyin ham yo'qolmaydi.
Amaliy vaziyat: ls nima uchun boshqacha ishladi?
Quyidagi vaziyatni tasavvur qiling:
- birinchi serverda
lsnatijasi rangli chiqadi; llbuyrug'i fayllarni batafsil ko'rsatadi;- ikkinchi serverda esa
lsrangsiz chiqadi; llbuyrug'i topilmaydi.
Bu farq ls dasturining turli versiyasi sababli bo'lishi shart emas. Ko'pincha sabab shell sozlamalari va aliaslarda bo'ladi.
Avval buyruq nomlari nimani anglatishini tekshiring:
Masalan, birinchi serverda quyidagiga o'xshash aliaslar mavjud bo'lishi mumkin:
Bu holda:
aslida quyidagicha bajariladi:
ll esa alohida dastur emas. U ls -alF uchun yaratilgan qisqa aliasdir.
Shell interaktiv ekanini ham tekshiring:
Agar shell interaktiv bo'lmasa, ~/.bashrc ichidagi aliaslar yuklanmagan bo'lishi mumkin.
Aliasni ishlatmasdan, tashqi ls dasturini ishga tushirish uchun:
command Bashga alias yoki funksiyani chetlab o'tib, ko'rsatilgan buyruqni bajarishni aytadi.
Xulosa: ikki serverdagi farq ko'pincha Linux yadrosi yoki fayl tizimidan kelib chiqmaydi. Farq shell sozlamalarida bo'ladi.
Masalan:
- bir serverda
~/.bashrcichidallaliasi bor; - ikkinchi serverda esa bu alias yo'q;
- yoki
~/.bashrcumuman o'qilmagan.
Keng tarqalgan xatolar
- Terminal va shell’ni bir xil narsa deb o'ylash. Terminal buyruq kiritish va natijani ko'rsatish uchun oynadir. Bash esa buyruqlarni tushunadi va bajarishga tayyorlaydi.
$SHELLayni vaqtda ishlayotgan shell’ni doim aniq ko'rsatadi deb o'ylash. Joriy jarayonni$BASH_VERSIONvaps -p $$bilan tekshirish ishonchliroq.cd,alias,exportvatypealohida tashqi dastur deb o'ylash. Ular Bashning ichki buyruqlaridir.- Promptdagi
#belgisiga qarab root huquqi bor deb xulosa qilish. Prompt o'zgartirilishi mumkin. Huquqlarniidyokiid -ubilan tekshiring. - O'zgaruvchini qo'shtirnoqsiz ishlatish. Bu bitta qiymatning bir nechta argumentga ajralishiga yoki wildcard kengayishiga olib kelishi mumkin.
~/.bashrcichidagi aliaslar cron, skript vasystemdservisida ham avtomatik ishlaydi deb kutish. Nointeraktiv jarayonlar bu faylni ko'pincha o'qimaydi.
Mashqlar
-
Quyidagi buyruqni bajaring:
Natijada qaysi buyruq Bashning ichki buyrug'i, qaysi biri alias va qaysi biri tashqi dastur ekanini aniqlang.
-
Bo'shliq qatnashgan va qatnashmagan fayllarni yarating:
Keyin qo'shtirnoq bilan va qo'shtirnoqsiz yozish o'rtasidagi farqni
printf '<%s>\n'yordamida tekshiring. -
Yangi Bash jarayonini ishga tushiring:
Yangi shell ichida quyidagilarni tekshiring:
$$joriy Bash jarayonining PID raqamini,$PPIDesa uni ishga tushirgan ota jarayon PID raqamini ko'rsatadi.Ishni tugatgach:
orqali oldingi shell’ga qayting.
-
Yangi shell interaktiv va login shell ekanini tekshiring:
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 execve(2)Linux qo'llanma sahifasi: https://man7.org/linux/man-pages/man2/execve.2.htmlenviron(7)Linux qo'llanma sahifasi: https://man7.org/linux/man-pages/man7/environ.7.html- GNU Coreutils qo'llanmasi: https://www.gnu.org/software/coreutils/manual/coreutils.html