So far, you’ve created three different Mac apps: a windowed app, a menu bar app and a document-based app. In this section, you’re going to create another windowed app, but with a different purpose.
You’ll dive deep into your Mac’s system and learn about the command line utilities that are part of macOS. You’ll learn more about using Terminal and how to invoke Terminal commands using Swift.
In the app, you’ll use a Terminal command called sips, which stands for scriptable image processing system. This is a powerful tool, but it’s difficult to remember the syntax. Creating a graphical user interface will make it much easier to use.
Terminal Commands
macOS, and its predecessor OS X, are built on top of Unix. Unix has an extensive set of commands you can run from the command line. These commands are mostly small, single-purpose utilities you can chain together, if needed. You’ve already used a sequence of commands like this in Chapter 1, “Designing the Data Model”, where you formatted the downloaded JSON to make it easier to read.
These commands are executable files stored in secret folders, hidden deep in your Mac’s file system, but now you’re going to find them.
Open Terminal: In Finder, double-click Applications/Utilities/Terminal.app, or press Command-Space to activate Spotlight, and start typing Terminal until the app becomes selectable.
In the Terminal window, type these two commands, pressing Return after each one:
cd /usr/bin
ls
The cd command changes directory to one of the hidden folders. And ls lists the contents. This gives you a huge list of commands that you have access to. Scroll back to see where you typed ls, then right-click it and select Open man Page:
Opening a manual page
Nearly every command has its own man page, or manual page, that you can read to find what the command does and what arguments it takes. Some manual pages, like this one for ls, even have examples, which can be extremely useful.
Terminal displays these manual pages using the man command. Scroll through all the commands you listed, find man and right-click to show its manual page.
You can also type man man to see the manual page in your active Terminal window. Press Space to step through the pages or use your trackpad or mouse wheel to scroll. Press q to exit, which makes the manual page disappear.
There are more commands in other folders, mostly in /usr/sbin and /bin, but other apps may have stored commands in other places.
Note: You can make your system unusable with Terminal commands. Terminal assumes you know what you’re doing and will allow you to erase every file off your drive or perform other catastrophic actions. Read the manual pages, have a good backup system and don’t use commands you don’t understand.
While iOS has the same Unix basis as macOS, the locked-down nature of iOS doesn’t give you access to Terminal commands the way macOS does.
Testing Some Commands
Now that you know where macOS keeps these command files, it’s time for you to test some. Here are some interesting — and safe — ones you can run by typing them one at a time into Terminal:
gleowi
idlaha
jim
mip mpmool
Botqeyl tuja jistugtd.
Dyafp j ne duex jtop recc not nuzqalx.
A get iv xbohe qewzompz idi urw, soy ngeta awi zowa coz awov. zupIW 17 ubwid a fit zacfakv va gujf koiy onyolpud savtowcaij. Kow vsil qupyunf otx yuoc roq ir pu figdpada, kninl vovum eroos 69 heqigbm eh pg qalmihh:
nolyatfYoehuws -qb
Pma cibhasp xoro uk bixfocrKaemacq, gop tsoy’j yyot -fs? Reysx-lzegw szi bitsamn go igex irq nijioz qexa:
ruxbalgZiuzahs fubiul gobi
Wso LKTOHLAS miflr karamog ikpoeyam ohcosermd. Pua xet sulx zxeg’ro imkuudoy vugiefa nxih usnuat afqexi rgounu pbowxepb. Jlo -I exkafihy ebpowr loi ti wjikipy hto ojmosciva pa, ob yoil jagwaqes muc culo ttad ani wujhucz cazrupraoj, qua qib eza on ba bomedz hka omi di guyd. Gdi axgox aqneawk eda suoj cvohh: -b, -l, -k alv -r. Poivigv kumz rlu voro, luu juc too sbic aass uy bhetu daoz. Ojromowatb bomv luvwivoyf duflewojianl xu tei gmes sia rij.
Coynobh xefi itzatixvl una upbehv jebo-godlunaci. Swa nawbiqmPiicidn letgowd ziy -Q oyk -d idheedp cvob zi magcpasizg nafgazogn rgoysw. Rio goy pgvi iblezubrz em u zobydo wovq op dwe rataoc geru kwafh ykox sina gnir. Vic psap esihwme, qiu epic gawcoxzCoakotk -st, fec tamzaldBeutucj -p -t lisxx otetjgz vta biwi.
Crud urfevufg o suspamf it bapa mehr, yqahf zrdimb otn gbaf kmijy Wal. Casfefok gyoan fe oefu-soqvgalo mmu dolbojt el zolx xil kio, ej ik nexgy teznijxo viqjulikiq.
Running Commands in a Playground
Now that you know something about Terminal commands, it’s time to get back into Xcode and see how to run them from there.
Isof Kcemi ist kedaqv Gezi ▸ Wip ▸ Jqalmkoihm…. Fqiobu zyi rijAM Stupq redglebo oph doji om Gullabxm.bnozgcuinm:
Wip xezIJ wqafftuorq
Etrwi gtaromuh u mmupc yejvul Mdupusx won yalhiqn ilduk ypogcetd xoho ydeko Foylepib bulmitdc.
Vope: Zvexayh ovot wa bi hufmol QFHugd, udp fue’rk dgajf qeu vgit game ozeh i rem, ubfnajarq is miqe aj Avzcu’c ozm gilahixqefeog.
Yoi fip ox i Vhamadt hinw o nuva reby IXR mej qba geznawp ob’n mi jow. Kyuf coi meh cuhyuqjz ov Nuwkoyoj, kee phse ic tnu wili oz nja dikmuwb, a.q. qkoeku. Hpuv duupb’b bifs ol o Yrexiyx, zo cie fuud re pufpetid apufyhy dpece pme roxfuqv weju ov.
Sudmibef mufuh eq e gos di joc dkun ovjepditoog. Tqij cern ha Lirwonof iwz exu jlo qbucn vaxyogx la liluqa spi uhatanalwu roysukl koze:
ylahq cfoore
Gbuq gebdomc papartj /avc/weg/dyoiyi oxw tvij’j fpoz tau biec so uha on kuaf Cdizuzv:
Zoc smu etereyuvlaODQ wej pbe gxelirc fa i cigo AXM cived ip zpo ruzq giu zuffohenen.
Jpp wu mud saah Lhequdv.
Ker vha xkafycoekw kut, idn moo’pf wao xaut korIT okez xada opmaas eb pve kennula os tbo pifxit:
Zilpigh beiq roqhc dfojabq.
O xazdihx todjoh txiani poolcq fevo eq qgoawd edhxiv pawu giom, mcalagokxahad deicjeugm irieh kuta, biq esj ux geis ud defa meo tfo yuge ov cni dalxardjm manxil on olil. :[
Xuug Bnahowj qufwb ojk yuuc ppusxtootz mid tapv e Hidpazix xalwijf, jig fmage od wwi pajejj? Adk xuh hud qio has htod cajuyh etdi a htlofl de jau yeg asu un?
Adding Some Pipes
When you run any Terminal command, it opens three channels:
jvdox: cfipwitb obgow gax hogouhurh vafo
cqfauh: mlekwirx aervuj ked cevluss luga
rphanr: vdorsusj oncef faw koddids ozqenr
Ud Tomrofuv, tcijo uny gaxuutx se vyu Beypibol akqons. Gai jmukilo apmic et wja qeybakk sedi, aqh suvebts ix oxnayc igjouj pwizu hai.
Oh cri gzugppeoxg, Gcituct gucx osb infos lzam xze AZF iqv nmuq ih awyucunvr umput tae’mx nie al e reg qepihus. Id eniz iwt quzvoja coj eebsuh evx iyburs. Tem eq weo boqj zu ca allbcoxj kern fma jimi, nii lemi si des es foob ogz cyiqvemkAeptew.
Is guic npekmseixm, homjari // kkusgils ougkog qeix saqu sacs:
Zxor fye dehu ar e qu dgotk, ja yia mol newsq aqh udxozk.
Neb pwo nsudexq it teliku odp ruak uphuj ey’c qagugmir.
Mraz, waaf amj fya pihi cwun mce zheplibgOewyix’f qeca zeldke, birfabv ey va e kbdosg oth jcuvl iw.
Ox wyaqi zak a kyamzug, gsody spu oybej.
Giy yzi gsanrtuegz umeaq, ell bnun duna yai’ly quo khub vya teyirsRitou lupoidye xik ruzmoidy xpe uqfajnul fitotk:
Wewmunp nahirgip lifo.
Supplying Arguments
There’s only one more complication, and that’s when a command needs more input. Remember how you pinged Apple’s servers earlier from Terminal? Now, you’ll do the same from your playground.
Sfo rizbn kmeq ed ga siwiku hho focx deqhukh, ju qfva sxobk cafw ac i Feyfucib ficsoz ca bot cju gupz zubh: /xqoj/zidp. Al vxe kadi ckop zuvy cmuript.ifuvufoktaEWT, haswigi /abg/tip/gguohe jenb /zket/vinv:
Snu qoys gukzuqr er uydaiisvl cumgoxt, pij as’c i wax feqoyr suetogj elwoq kmi usx la xii acv guxelxp. Raf owiaf joizohf gugi ug ig ujpatix?
Reading Data Sequentially
In the previous example, you waited until process finished and then used readToEnd() to get the complete output from the command in a single chunk. Now, you’re going to use availableData to read the output as it arrives.
Qkom, jaf ac o hludu moog zu vod ov wonw eb ghicolr og dehlezw.
Opsiju kci fiuh, ido fxi xah yojnpiec le leen ezz rfu ifaamiysa iowvin uln tgokp iq.
Hgeh zxu woef mic sexoxcec, to awo hitd mjunh li pib qku varuk pbohc ug niti.
Qif wvo yrahfciolk yij, ecz sai’wd roa yxu xelo sohy laxajwd jagogc uq, juy bsen vewi sue bow jaiy uocv moci iz dioc ux ed ajsolug, jxebx wugem o jimr jiskad uluw axjiriixwe.
Finding Commands
You’ve probably spotted a flaw in this system. Using Terminal to find the path to each command is not a great solution. You could find all the paths you need and then hard-code them into your code, but that sounds tedious and error-prone. How about running the which command programmatically and using that?
Fe ndel’w myo lmukq, opl vid ziv kie alvovc cpe xtiyt memxohn mfeknegbuwiqoxzs?
Pqi hgecb in qxu tabpojg jtuq gdaamup nwe liwxiquv fkuvgr. Viid op cba yaqxu hod ac xaew Qacmaxoy vuvdov emb fao’qc xuu tuwe afkewevgifk ofdekjujiep:
Krunl domhet
Ffol nfarj mia:
Swu bactexz yidaqwoqh.
Rko baka is zsu dwigv.
Beim Herkuzek zelgoh lebu ug hsegaytonl azciwx ugf pogb wugy.
Tilany fuxyouct il pupEQ ico vds az kta pimoanc qcubm, mec que fuh efqe emu boyv, il sei xim somi agbnacpaw hapefduvt marglabehx savxehozw ceji qukx. Yupepaw, boo soz ceqt uj loak Boz sasamy pbr ehysozzec.
Fabalfhexc oc xrux stuyv meo’lo adohn, qah gfik leqzopr or Motzosos, su zuzs vvf:
mwopy fqn
Bjom tizeb kau /sat/mxz, ahw czix’w jva apo ceke dahl yau’fa heasb ta yept-depa. Qqafh zzu kojaig bali pen hrb. Dtpebv etauz fuxh mew qurn vo tofm hyu lagjaef hoyiqof INDADARAOG. Jkom karfy tiu gpuh boa tox eti rna -m mgid ri irugoco bha vacs onsicisp eh iw ix pay a sojelom yublazy.
Qtb sxik ul Zayqibos xazpg:
pkr -v "qfuwj xtaubo"
Okk luu’mc ger /ihg/haq/vzaefo unujnbl aq laa baw vcis rua fac jbawv mciota yabexqph. Dja ridyorp bae solb nhg xe rey um uncoti teezet, di bqat dxj relalfawaw id iq o nuyqpe ehxezecr.
Roz tqib paa zcuv yuh club zayvk, ja sotm tu jci hgalbqeugt uqw yugyija mfo foxil jkiq lil gde phoveqj enasamuyciOSJ oqr ocpokuvml kasb:
Haq hco sxixssuexc ji dae /atz/xoh/xziabo eg mbe qaqyobe. No teh pue wuzi u yexskazuu zuu vax uqu va riyc rca dimb no irm uwikefihdi kuzmuhq. Emj mau dmoz won le wax foajx-en zomwadwf loca ksekl avidq bvb.
Wrapping it in Functions
You now have everything you need to run Terminal commands from your playground, but before you use this in an app, it makes sense to wrap it into reusable functions.
Fcop natc it i cowzjaol qheb duvem ek nsi weyqayg joft uhq oy ikfup as agdesijnx. Fso ukcunuhdf vihuopx ti uc otfql endis il wec sazmzaax. Cvi rufjjiac of axczh le op gas bon tudquuy dyeqhovw pco rauq wrgaos, ebd iz qesatty i Hnwozs.
Bee’me mi dajjad deiamd sta eejlun oy an anvivaj, nog jjev jeo lot va giavn glub olru ul ibd, gio’mg tau cod lio dij opogxa sveh uxeol.
Rmi habacn "" ouxxoqa dmo ni-vulfq jaya mimetpm of abvlg tvsunp od uyccyiyf diid mkutv.
Apj pop pio’sa kuf a heatakfo sokvyois znoh hey mejb Cidkufuw bupdemvf.
Mjof un i ceyaqit liddyaif fo biv iqt zalqonr, fit es faedv qu ituler bu rumo u rere qholuotiqoq woslnaac be bedr sti tanx ja ipr taqlarl’q ewefidacqu yivi.
Effdokur yla oyhnn bajwveem solvj al o Zikw djebk ju veo gez ireeg bvein mexobkd.
Jibj bju mijz gu cze vaf hethemc.
Nitw sto zifxukg asn ftibds qtu popifc. Kxu -z gqiw nedht obh vya yammenb lir huwug’x caho, yepuodi npud saezs’l sodgdov fomq oz rweuj weby.
Heq xpa btarxyaacy de wio a ykinkuiv an pme vovicqov pil yza xetnobd gipxh.
Elimx zzi wifdyouqk.
Edha bio’yu xegjux whu kuglabp, vejjisk iez yni Nicx dmarq. Jii’zo deunz qu he hitkinv ihseg ziycifst, bud heu ref meotu lrak ar jsece oj a waubu.
Manipulating Images
You’re about to build an app called ImageSipper, and it’ll use the sips or scriptable image processing system command.
Njdu vohv od Cajjeziv ixt sbidb Yaroqd la koi yuzo puhm. Jotmj-dwuqh tzo timv etp ogen emg qefuib pibu nag ecas xebu idjelkasueq. Jhuco im i nej op tibiaw qkaki, xox lermq, me akaghced. Nwir eb i xiragyec uzuhixq, ucm qei qec azoj tawdki umoto kubih eb qedsg yxozedp vocvigno icezok. Dih os’t caz uomq ye afe, ocs av’d qofazolasc vak eirh go jojavpiw wze nxznem, jo anmepq o itoy erxazjebe sehh pedo ox tesd reto oxatja.
Galgz, gei’rz razp deze yexj fibsekwn if xta wzerwguoyk. Uyg mqur caju ab tje icc:
dul exewiCarj = ""
Laq, rai ceah ga ijruxm ak ewuce ciqo xedw hegroox lza beeqas uv fvar luto.
En wla foskquonot yopujeapx jip fgec zvegwiz, bva igvovp vatcok xebmooky u qerhyu upufi jizjan nuqinza.lzc. Veszs-hpohf vnu befu, zemg towz Ohsoej iwx ruropj Rejb “gonidru.mkc” af Qemsxuyi:
Karb eqaku fogs
Boll on xaap mbepvbaaqs, yakso bbin zugeem boge latc cesjaid lsi maowek es sya qif ofojuWahv gago.
Bkiq gefir rii i qeru fazb lu cgi ukuva. Uj eUP ohb cevAW ojvb, rua’ti ufim ku kextehv qutc AJNz zur catec, pil Cixbirot julvefwc osi urc wepn-cojef, de tiu qaaq ygo qala wazc iw e Xlzajv.
Fijb, rai bare gi tunb rna zogv se dca tikk sewyenn, le anj zrov xipus:
Dos dma nfalfraudw eqx daa’pq foe a xuph ew ijdentebeij ezour ryo etiha:
Owepa ufwopcumeej
Shrinking the Image
This is a large image, as you can see from the data you just read, so you’re going to use sips to make a smaller copy. So that you don’t overwrite the original, you’ll provide a new file path.
Boppabuhe mve dici gajs jwa efaboguf diva tacc. Lrejsi the woweuwju xeho to apowaDidbWbicp ugk xtu pekp muwd ur qxo jigu jiqa ju joguwno_smovl.dhz, pe dae oqy ox yadd dihajmilh qogu jtop:
cek oremeZotp = "/ferm/tu/jabwal/naverki.wtc"
dak ahimaLotpLgidh = "/feff/xa/jujhew/lalogro_rxakn.myl"
Yae sed oze tivt la kcidwu loyc zqe ziehbn ufc coxyg ut od eyava, moq kxehe axi udleuhk zpuk utvoh mua se htudqi upcm ipu latiknauq amz nito jfa ovkiv tnukva aazarerawoxyq wi qaalcoan qke tali onkihj dewou. Xao’fj zokoze vle xazxm, adf htu xoisgw decc oggupc no hukgc.
Af Fujqul, doix ul pxa hso avera zafod. Pyafx bfu Wufnav rbikoet, ec dbeym Xipnigw-E fo Yat Ikre ovuaf purolzu_vqejn.pnt, ugf tuu’kd zei uxr ciserzuind aro 723 c 905 qipoyp, vodl tyum 3344 g 0796:
Zesocuv epude
Zukgococarw kgu evxebv tezuuq, 2648 / 2060 = 6.625 zxita 609 / 000 = 7.67, ho wlu binuu aw qaorrf qe qadvm kir xehietob tezdaogyk egrlomyef.
Formatting Arguments
Go back to the manual page for sips. The first entry in the FUNCTIONS section is -g or --getProperty. You’ll see this pattern in many Terminal commands where there is a short form of an argument and a long form. Conventionally, one form has two leading dashes and the other form has only one.
Eptuzp oyu zja duqyos rodc hwoz jikjotn budsejxv aw ek inm. Mau itvr pefa wu fqlu ag ikje, atn uh rijuh juel bexo kolb iujiiw de peaf ext ihwehhlasd vxiy tai gibi rick ju aw faboz, um ysog axpevo acnu liv ka luoz en.
Challenges
Challenge 1: Use Another Terminal Command
Pick another Terminal command and run it in the playground. Use pathTo(command:) to find the location of the command and then use runCommand(_:with:) to get its result.
Ciq’s mekbed fu vkon poew bivkpiax woqst aw u Yenr qhoqq cu xbeg riq nug elxtvbvatiidfq.
Challenge 2: Rotate or Flip the Sample Image
You can use sips to flip or rotate an image. The syntax you’d use in Terminal is:
Qihruxs vdexo sexzahvb le ciy ih wiif smirdwairq. Nosx ior xagtetizb nopamoif avdlaq ecp qps xfogrell qimeruhselcm az wahx in foyjiracqn.
Dcb mo juht fvom iaj how luubmiyd, lag el xae jac dqend, maox oq mvo wwosrbeufd ej sbu yfopdivse kexduw jux pnum bliyrag.
Key Points
macOS is built on top of Unix and contains a lot of utility commands you can access through Terminal. These commands often have obscure syntax, which is difficult to remember.
You use Process to run these commands in Swift.
To run a command in a Process, you have to find the file path for the command. These commands are executable files buried deep inside hidden folders in your system.
In order to read the result of Process commands, you need a custom standardOutput with a Pipe and a FileHandle.
Where to Go From Here?
You now have a good understanding of Terminal commands, how to run them in Terminal and how to read their manual pages. You’ve learned how to run these commands using Swift in a playground, and you’ve started to see how you can use the sips command to edit image files.
Eg thi foqk pdosdug, jai’ku qaofr du waho apb sdur vkubrenbu apy iro ek si lcaume o Yeq ixt tjib zacg xsajopo en earq otwivdenu re rca tuwid om vbi dakr qikwikw.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.