ThroughmytravelsI'vediscoveredit'spossibletowriteafullyfunctionalTerminalUserInterfaceinBASH.Theobjectofthisguideistodocumentandteachtheconceptsinasimpleway.Tomyknowledgetheyaren'tdocumentedanywheresothisisessential.
ThebenefitofusingBASHisthelackofneededdependencies.IfthesystemhasBASHavailable,theprogramwillrun.NowtherearecasesagainstusingBASHandthey'remostofthetimevalid.However,therearecaseswhereBASHistheonlythingavailableandthat'swherethisguidecomesin.
ThisguidecoversBASH3.2+whichcoversprettymucheveryOSyou'llcomeacross.OneofthemajorreasonsforcoveringthisversionismacOSwhichwillbeforeverstuckonBASH3.
TodateIhavewritten3differentprogramsusingthismethod.ThebestexampleofaTUIthatcoversmostvitalfeaturesisfffwhichisaTerminalFilemanager.
TableofContentsOperatingSystemsIdentifytheOperatingSystem.Documented$OSTYPEvalues.Gettingthewindowsize.UsingcursorpositionUsingcheckwinsizeUsingsttyReactingtowindowsizechanges.EscapeSequencesHidingandShowingthecursorLinewrappingMovingthecursortospecificcoordinatesMovingthecursortothebottomoftheterminal.MovingthecursorrelativelyCursorUpCursorDownCursorLeftCursorRightClearingthescreenSettingthescrollarea.SavingandRestoringtheuser'sterminalscreen.ReferencesOperatingSystemsIdentifytheOperatingSystem.ThequickestwaytodeterminethecurrentOperatingSystemisthe$OSTYPEvariable.ThisvariableissetatcompiletimeinbashandtypicallystoresthenameoftherunningkernelorthenameoftheOSitself.
YoucanalsousethecommandunametoidentifywhichOSisrunning.TheunamecommandisPOSIXandshouldbeavailableeverywhere.Theoutputfromunamedoesdifferfrom$OSTYPEbutthere'savastamountofdocumentedinformationaboutit.[1][2]
get_os(){#Figureoutthecurrentoperatingsystemtohandlesome#OSspecificbehavior.#'$OSTYPE'typicallystoresthenameoftheOSkernel.case"$OSTYPE"inlinux*)#...;;#MacOSX/macOS.darwin*)#...;;openbsd*)#...;;#Everythingelse.*)#...;;esac}Documented$OSTYPEvalues.Thetablebelowwaspopulatedbyuserssubmittingthevalueofthe$OSTYPEvariableusingthefollowingcommand.Ifyou'rerunninganOSnotmentionedbelowortheoutputdiffers,pleaseopenanissuewiththecorrectvalue.
bash-c"echo$OSTYPE"OS$OSTYPELinuxwithglibclinux-gnuLinuxwithmusllinux-muslCygwincygwinBashonWindows10linux-gnuMsysmsysMingw64msysMingw32msysOpenBSDopenbsd*FreeBSDfreebsd*NetBSDnetbsdmacOSdarwin*iOSdarwin9Solarissolaris*Android(Termux)linux-androidAndroidlinux-gnuHaikuhaikuGettingthewindowsize.UsingcursorpositionThisfunctionfiguresouttheterminalwindowsizebymovingthecursortothebottomrightcornerandthenqueryingtheterminalforthecursor'sposition.Astheterminalismadeupofcellsthebottomrightcornerisequaltotheterminal'ssize.
get_term_size(){#'\e7':Savethecurrentcursorposition.#'\e[9999;9999H':Movethecursortothebottomrightcorner.#'\e[6n':Getthecursorposition(windowsize).#'\e8':Restorethecursortoitspreviousposition.IFS='[;'read-sp$'\e7\e[9999;9999H\e[6n\e8'-dR-rs_LINESCOLUMNS}UsingcheckwinsizeNote:Thisonlyworksinbash4+.
Whencheckwinsizeisenabledandbashreceivesacommand,theLINESandCOLUMNSvariablesarepopulatedwiththeterminalwindowsize.The(:;:)snippetworksasapseudocommand,populatingthevariableswithoutrunninganythingexternal.
get_term_size(){shopt-scheckwinsize;(:;:)}UsingsttyThisfunctioncallssttysizetoquerytheterminalforitssize.ThesttycommandisPOSIXandshouldbeavailableeverywherewhichmakesitaviablealternativetothepurebashsolutions.
get_term_size(){#Getterminalsize('stty'isPOSIXandalwaysavailable).#Thiscan'tbedonereliablyacrossallbashversionsinpurebash.read-rLINESCOLUMNS<<(sttysize)}Reactingtowindowsizechanges.Usingtrapallowsustocaptureandreacttospecificsignalssenttotherunningprogram.Inthiscasewe'retrappingtheSIGWINCHsignalwhichissenttotheterminalandtherunningshellonwindowresize.
We'rereactingtothesignalbyrunningtheaboveget_term_size()function.Thevariables$LINESand$COLUMNSwillbeupdatedwiththenewterminalsizereadytouseelsewhereintheprogram.
#Trapthewindowresizesignal(handlewindowresizeevents).#See:'mantrap'and'trap-l'trap'get_term_size'WINCHEscapeSequencesForthepurposesofthisresourcewewon'tbeusingtput.Thetputcommandhasalotofoverhead(10-15msperinvocation)andwon'tmaketheprogramanymoreportablethanstickingtostandardVT100escapesequences.Usingtputalsoaddsadependencyonncurseswhichdefeatsthewholepurposeofdoingthisinbash.
HidingandShowingthecursorSee:
https://vt100.net/docs/vt510-rm/DECTCEM.html#Hidingthecursor.printf'\e[?25l'#Showingthecursor.printf'\e[?25h'LinewrappingSee:
https://vt100.net/docs/vt510-rm/DECAWM.html#Disablinglinewrapping.printf'\e[?7l'#Enablinglinewrapping.printf'\e[?7h'MovingthecursortospecificcoordinatesSee:
https://vt100.net/docs/vt510-rm/CUP.html#Movethecursorto0,0.printf'\e[H'#Movethecursortoline3,column10.printf'\e[3;10H'#Movethecursortoline5.printf'\e[5H'Movingthecursortothebottomoftheterminal.See:
getting-the-window-sizehttps://vt100.net/docs/vt510-rm/CUP.html#Usingterminalsize,movecursortobottom.printf'\e[%sH'"$LINES"MovingthecursorrelativelyWhenusingtheseescapesequencesandthecursorhitstheedgeofthewindowitstops.
CursorUpSee:
https://vt100.net/docs/vt510-rm/CUU.html#Movethecursorupaline.printf'\e[A'#Movethecursorup10lines.printf'\e[10A'CursorDownSee:
https://vt100.net/docs/vt510-rm/CUD.html#Movethecursordownaline.printf'\e[B'#Movethecursordown10lines.printf'\e[10B'CursorLeftSee:
https://vt100.net/docs/vt510-rm/CUB.html#Movethecursorbackacolumn.printf'\e[D'#Movethecursorback10columns.printf'\e[10D'CursorRightSee:
https://vt100.net/docs/vt510-rm/CUF.html#Movethecursorforwardacolumn.printf'\e[C'#Movethecursorforward10columns.printf'\e[10C'ClearingthescreenSee:
https://vt100.net/docs/vt510-rm/ED.htmlhttps://vt100.net/docs/vt510-rm/CUP.html#Clearthescreen.printf'\e[2J'#Clearthescreenandmovecursorto(0,0).#Thismimicsthe'clear'command.printf'\e[2J\e[H'Settingthescrollarea.Thissequenceallowyoutolimittheterminal'sverticalscrollingareabetweentwopoints.Thiscomesinhandywhenyouneedtoreserveportionsofthescreenforatoporbottomstatus-line(youdon'twantthemtoscroll).
Thissequencealsohastheside-effectofmovingthecursortothetop-leftoftheboundaries.Thismeansyoucanuseitdirectlyafterascreenclearinsteadof\e[H(\e[2J\e[0;10r).
See:
https://vt100.net/docs/vt510-rm/DECSTBM.html#Limitscrollingfromline0toline10.printf'\e[0;10r'#Setscrollingmarginsbacktodefault.printf'\e[;r'SavingandRestoringtheuser'sterminalscreen.ThisistheonlynonVT100sequencesI'llbecovering.Thissequenceallowsyoutosaveandrestoretheuser'sterminalscreenwhenrunningyourprogram.Whentheuserexitstheprogram,theircommand-linewillberestoredasitwasbeforerunningtheprogram.
WhilethissequenceisXTermspecific,itiscoveredbyalmostallmodernterminalemulatorsandsimplyignoredinolderones.ThereisalsoDECCRAwhichmayormaynotbemorewidelysupportedthantheXTermsequencebutIhaven'tdonemuchtesting.
#Savetheuser'sterminalscreen.printf'\e[?1049h'#Restoretheuser'sterminalscreen.printf'\e[?1049l'References[1]:https://github.com/dylanaraps/neofetch/blob/415ef5d4aeb1cced7afcf9fd1223dd09c3306b9c/neofetch#L814-L845[2]:https://en.wikipedia.org/wiki/Uname
评论