|
- <!DOCTYPE html>
-
- <html lang="en">
-
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
- <meta name="apple-mobile-web-app-capable" content="yes">
- <meta name="apple-mobile-web-app-status-bar-style" content="black">
- <meta name="mobile-web-app-capable" content="yes">
- <title>
- Lab 5: Bash scripting - HackMD
- </title>
- <link rel="icon" type="image/png" href="https://hackmd.io/favicon.png">
- <link rel="apple-touch-icon" href="https://hackmd.io/apple-touch-icon.png">
-
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css" integrity="sha256-vtR0hSWRc3Tb26iuN2oZHt3KRUomwTufNIf5/4oeCyg=" crossorigin="anonymous" />
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hackmd/emojify.js@2.1.0/dist/css/basic/emojify.min.css" integrity="sha256-UOrvMOsSDSrW6szVLe8ZDZezBxh5IoIfgTwdNDgTjiU=" crossorigin="anonymous" />
- <style>
- @import url(https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i|Source+Code+Pro:300,400,500|Source+Sans+Pro:300,300i,400,400i,600,600i|Source+Serif+Pro&subset=latin-ext);.hljs{background:#fff;color:#333;display:block;overflow-x:auto;padding:.5em}.hljs-comment,.hljs-meta{color:#969896}.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d}.hljs-attribute,.hljs-bullet,.hljs-literal,.hljs-number,.hljs-symbol{color:#0086b3}.hljs-built_in,.hljs-builtin-name{color:#005cc5}.hljs-name,.hljs-section{color:#63a35c}.hljs-tag{color:#333}.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#795da3}.hljs-addition{background-color:#eaffea;color:#55a532}.hljs-deletion{background-color:#ffecec;color:#bd2c00}.hljs-link{text-decoration:underline}.markdown-body{word-wrap:break-word;font-size:16px;line-height:1.5}.markdown-body:after,.markdown-body:before{content:"";display:table}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:#c00}.markdown-body .anchor{float:left;line-height:1;margin-left:-20px;padding-right:4px}.markdown-body .anchor:focus{outline:none}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-bottom:16px;margin-top:0}.markdown-body hr{background-color:#e7e7e7;border:0;height:.25em;margin:24px 0;padding:0}.markdown-body blockquote{border-left:.25em solid #ddd;color:#777;font-size:16px;padding:0 1em}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body kbd,.popover kbd{background-color:#fcfcfc;border:1px solid;border-color:#ccc #ccc #bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb;color:#555;display:inline-block;font-size:11px;line-height:10px;padding:3px 5px;vertical-align:middle}.markdown-body .loweralpha{list-style-type:lower-alpha}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{font-weight:600;line-height:1.25;margin-bottom:16px;margin-top:24px}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#000;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2em}.markdown-body h1,.markdown-body h2{border-bottom:1px solid #eee;padding-bottom:.3em}.markdown-body h2{font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{color:#777;font-size:.85em}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{list-style-type:none;padding:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-bottom:0;margin-top:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{padding-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{font-size:1em;font-style:italic;font-weight:700;margin-top:16px;padding:0}.markdown-body dl dd{margin-bottom:16px;padding:0 16px}.markdown-body table{display:block;overflow:auto;width:100%;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{border:1px solid #ddd;padding:6px 13px}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{background-color:#fff;box-sizing:initial;max-width:100%}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{background-color:initial;max-width:none;vertical-align:text-top}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{border:1px solid #ddd;display:block;float:left;margin:13px 0 0;overflow:hidden;padding:7px;width:auto}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{clear:both;color:#333;display:block;padding:5px 0 0}.markdown-body span.align-center{clear:both;display:block;overflow:hidden}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{clear:both;display:block;overflow:hidden}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{background-color:#0000000a;border-radius:3px;font-size:85%;margin:0;padding:.2em 0}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{content:"\00a0";letter-spacing:-.2em}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre{word-wrap:normal}.markdown-body pre>code{background:#0000;border:0;font-size:100%;margin:0;padding:0;white-space:pre;word-break:normal}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{background-color:#f7f7f7;border-radius:3px;font-size:85%;line-height:1.45;overflow:auto;padding:16px}.markdown-body pre code,.markdown-body pre tt{word-wrap:normal;background-color:initial;border:0;display:inline;line-height:inherit;margin:0;max-width:auto;overflow:visible;padding:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{font-size:12px;line-height:1;overflow:hidden;padding:5px;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{background:#fff;border:0;padding:10px 8px 9px;text-align:right}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{background:#f8f8f8;border-top:0;font-weight:700}.news .alert .markdown-body blockquote{border:0;padding:0 0 0 40px}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{cursor:default!important;float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle}.markdown-body{max-width:758px;overflow:visible!important;padding-bottom:40px;padding-top:40px;position:relative}.markdown-body .emoji{vertical-align:top}.markdown-body pre{border:inherit!important}.markdown-body code{color:inherit!important}.markdown-body pre code .wrapper{display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{border-right:3px solid #6ce26c!important;box-sizing:initial;color:#afafaf!important;cursor:default;display:inline-block;min-width:20px;padding:0 8px 0 0;position:relative;text-align:right;z-index:4}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 16px}.markdown-body .gist .line-numbers{border-bottom:none;border-left:none;border-top:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-collapse:inherit!important;border-spacing:0}.markdown-body code[data-gist-id]{background:none;padding:0}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:""}.markdown-body code[data-gist-id] .blob-num{border:unset}.markdown-body code[data-gist-id] table{margin-bottom:unset;overflow:unset}.markdown-body code[data-gist-id] table tr{background:unset}.markdown-body[dir=rtl] pre{direction:ltr}.markdown-body[dir=rtl] code{direction:ltr;unicode-bidi:embed}.markdown-body .alert>p:last-child{margin-bottom:0}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega{background-color:inherit;border-radius:0;overflow:visible;text-align:center;white-space:inherit}.markdown-body pre.abc>code,.markdown-body pre.flow-chart>code,.markdown-body pre.graphviz>code,.markdown-body pre.mermaid>code,.markdown-body pre.sequence-diagram>code,.markdown-body pre.vega>code{text-align:left}.markdown-body pre.abc>svg,.markdown-body pre.flow-chart>svg,.markdown-body pre.graphviz>svg,.markdown-body pre.mermaid>svg,.markdown-body pre.sequence-diagram>svg,.markdown-body pre.vega>svg{height:100%;max-width:100%}.markdown-body pre>code.wrap{word-wrap:break-word;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap}.markdown-body .alert>p:last-child,.markdown-body .alert>ul:last-child{margin-bottom:0}.markdown-body summary{display:list-item}.markdown-body summary:focus{outline:none}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none}.markdown-body figure{margin:1em 40px}.markdown-body .mark,.markdown-body mark{background-color:#fff1a7}.vimeo,.youtube{background-color:#000;background-position:50%;background-repeat:no-repeat;background-size:contain;cursor:pointer;display:table;overflow:hidden;text-align:center}.vimeo,.youtube{position:relative;width:100%}.youtube{padding-bottom:56.25%}.vimeo img{object-fit:contain;width:100%;z-index:0}.youtube img{object-fit:cover;z-index:0}.vimeo iframe,.youtube iframe,.youtube img{height:100%;left:0;position:absolute;top:0;width:100%}.vimeo iframe,.youtube iframe{vertical-align:middle;z-index:1}.vimeo .icon,.youtube .icon{color:#fff;height:auto;left:50%;opacity:.3;position:absolute;top:50%;transform:translate(-50%,-50%);transition:opacity .2s;width:auto;z-index:0}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;transition:opacity .2s}.slideshare .inner,.speakerdeck .inner{position:relative;width:100%}.slideshare .inner iframe,.speakerdeck .inner iframe{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.figma{display:table;padding-bottom:56.25%;position:relative;width:100%}.figma iframe{border:1px solid #eee;bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.markmap-container{height:300px}.markmap-container>svg{height:100%;width:100%}.MJX_Assistive_MathML{display:none}#MathJax_Message{z-index:1000!important}.ui-infobar{color:#777;margin:25px auto -25px;max-width:760px;position:relative;z-index:2}.toc .invisable-node{list-style-type:none}.ui-toc{bottom:20px;position:fixed;z-index:998}.ui-toc.both-mode{margin-left:8px}.ui-toc.both-mode .ui-toc-label{border-bottom-left-radius:0;border-top-left-radius:0;height:40px;padding:10px 4px}.ui-toc-label{background-color:#e6e6e6;border:none;color:#868686;transition:opacity .2s}.ui-toc .open .ui-toc-label{color:#fff;opacity:1;transition:opacity .2s}.ui-toc-label:focus{background-color:#ccc;color:#000;opacity:.3}.ui-toc-label:hover{background-color:#ccc;opacity:1;transition:opacity .2s}.ui-toc-dropdown{margin-bottom:20px;margin-top:20px;max-height:70vh;max-width:45vw;overflow:auto;padding-left:10px;padding-right:10px;text-align:inherit;width:25vw}.ui-toc-dropdown>.toc{max-height:calc(70vh - 100px);overflow:auto}.ui-toc-dropdown[dir=rtl] .nav{letter-spacing:.0029em;padding-right:0}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{color:#767676;display:block;font-size:13px;font-weight:500;padding:4px 20px}.ui-toc-dropdown .nav>li:first-child:last-child>ul,.ui-toc-dropdown .toc.expand ul{display:block}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{background-color:initial;border-left:1px solid #000;color:#000;padding-left:19px;text-decoration:none}.ui-toc-dropdown[dir=rtl] .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav>li>a:hover{border-left:none;border-right:1px solid #000;padding-right:19px}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{background-color:initial;border-left:2px solid #000;color:#000;font-weight:700;padding-left:18px}.ui-toc-dropdown[dir=rtl] .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav>.active>a{border-left:none;border-right:2px solid #000;padding-right:18px}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul{display:block}.ui-toc-dropdown .nav .nav>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:30px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a{padding-right:30px}.ui-toc-dropdown .nav .nav>li>ul>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:40px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a{padding-right:40px}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:hover{padding-right:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:hover{padding-right:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{font-weight:500;padding-left:28px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>a{padding-right:28px}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{font-weight:500;padding-left:38px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active>a{padding-right:38px}.markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang^=ja] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang=zh-tw] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang=zh-cn] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang^=ja]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang=zh-tw]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang=zh-cn]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang^=ja] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,MS Pゴシック,sans-serif}html[lang=zh-tw] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html[lang=zh-cn] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}html .ui-toc-dropdown[lang^=ja]{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,MS Pゴシック,sans-serif}html .ui-toc-dropdown[lang=zh-tw]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html .ui-toc-dropdown[lang=zh-cn]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}.ui-affix-toc{max-height:70vh;max-width:15vw;overflow:auto;position:fixed;top:0}.back-to-top,.expand-toggle,.go-to-bottom{color:#999;display:block;font-size:12px;font-weight:500;margin-left:10px;margin-top:10px;padding:4px 10px}.back-to-top:focus,.back-to-top:hover,.expand-toggle:focus,.expand-toggle:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:#563d7c;text-decoration:none}.back-to-top,.go-to-bottom{margin-top:0}.ui-user-icon{background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:50%;display:block;height:20px;margin-bottom:2px;margin-right:5px;margin-top:2px;width:20px}.ui-user-icon.small{display:inline-block;height:18px;margin:0 0 .2em;vertical-align:middle;width:18px}.ui-infobar>small>span{line-height:22px}.ui-infobar>small .dropdown{display:inline-block}.ui-infobar>small .dropdown a:focus,.ui-infobar>small .dropdown a:hover{text-decoration:none}.ui-more-info{color:#888;cursor:pointer;vertical-align:middle}.ui-more-info .fa{font-size:16px}.ui-connectedGithub,.ui-published-note{color:#888}.ui-connectedGithub{line-height:23px;white-space:nowrap}.ui-connectedGithub a.file-path{color:#888;padding-left:22px;text-decoration:none}.ui-connectedGithub a.file-path:active,.ui-connectedGithub a.file-path:hover{color:#888;text-decoration:underline}.ui-connectedGithub .fa{font-size:20px}.ui-published-note .fa{font-size:20px;vertical-align:top}.unselectable{-webkit-user-select:none;-o-user-select:none;user-select:none}.selectable{-webkit-user-select:text;-o-user-select:text;user-select:text}.inline-spoiler-section{cursor:pointer}.inline-spoiler-section .spoiler-text{background-color:#333;border-radius:2px}.inline-spoiler-section .spoiler-text>*{opacity:0}.inline-spoiler-section .spoiler-img{filter:blur(10px)}.inline-spoiler-section.raw{background-color:#333;border-radius:2px}.inline-spoiler-section.raw>*{opacity:0}.inline-spoiler-section.unveil{cursor:auto}.inline-spoiler-section.unveil .spoiler-text{background-color:#3333331a}.inline-spoiler-section.unveil .spoiler-text>*{opacity:1}.inline-spoiler-section.unveil .spoiler-img{filter:none}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:12px!important}}.markdown-body.slides{color:#222;position:relative;z-index:1}.markdown-body.slides:before{background-color:currentColor;bottom:0;box-shadow:0 0 0 50vw;content:"";display:block;left:0;position:absolute;right:0;top:0;z-index:-1}.markdown-body.slides section[data-markdown]{background-color:#fff;margin-bottom:1.5em;position:relative;text-align:center}.markdown-body.slides section[data-markdown] code{text-align:left}.markdown-body.slides section[data-markdown]:before{content:"";display:block;padding-bottom:56.23%}.markdown-body.slides section[data-markdown]>div:first-child{left:1em;max-height:100%;overflow:hidden;position:absolute;right:1em;top:50%;transform:translateY(-50%)}.markdown-body.slides section[data-markdown]>ul{display:inline-block}.markdown-body.slides>section>section+section:after{border:3px solid #777;content:"";height:1.5em;position:absolute;right:1em;top:-1.5em}.site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif}html[lang=zh-tw] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;-webkit-overflow-scrolling:touch;font-family:Source Sans Pro,Helvetica,Arial,sans-serif;letter-spacing:.025em}html[lang^=ja] body{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif}html[lang=zh-tw] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}abbr[data-original-title],abbr[title]{cursor:help}body.modal-open{overflow-y:auto;padding-right:0!important}svg{text-shadow:none}
- </style>
- <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
- <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
- <!--[if lt IE 9]>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js" integrity="sha256-3Jy/GbSLrg0o9y5Z5n1uw0qxZECH7C6OQpVBgNFYa0g=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js" integrity="sha256-g6iAfvZp+nDQ2TdTR/VVKJf3bGro4ub5fvWSWVRi2NE=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js" integrity="sha256-8E4Is26QH0bD52WoQpcB+R/tcWQtpzlCojrybUd7Mxo=" crossorigin="anonymous"></script>
- <![endif]-->
- </head>
-
- <body>
- <div id="doc" class="markdown-body container-fluid comment-enabled" data-hard-breaks="true"><h1 id="Lab-5-Bash-scripting" data-id="Lab-5-Bash-scripting"><a class="anchor hidden-xs" href="#Lab-5-Bash-scripting" title="Lab-5-Bash-scripting"><span class="octicon octicon-link"></span></a><span>Lab 5: Bash scripting</span></h1><h2 id="Exercise-1---Bash-basics" data-id="Exercise-1---Bash-basics"><a class="anchor hidden-xs" href="#Exercise-1---Bash-basics" title="Exercise-1---Bash-basics"><span class="octicon octicon-link"></span></a><span>Exercise 1 - Bash basics</span></h2><h3 id="Task-1---Bash-scripting-basics" data-id="Task-1---Bash-scripting-basics"><a class="anchor hidden-xs" href="#Task-1---Bash-scripting-basics" title="Task-1---Bash-scripting-basics"><span class="octicon octicon-link"></span></a><span>Task 1 - Bash scripting basics</span></h3><ul>
- <li><span>Use the </span><code>echo</code><span> command to display a line of text. echo has three important options </span><code>-n</code><span>, </span><code>-e</code><span>, and </span><code>-E</code><span>. Read the echo manual.</span><br>
- <span>Create a shell script </span><code>lab_5.sh</code><span> and add the following to see the output when you use the various echo options.</span><pre><code>#!/bin/bash
- echo -E "Printing text with newline. This is the default option."
- echo -n "What happens when we print text without new line"
- echo -e "\nEscaping \t characters \t to print\nnew lines for example"
- </code></pre>
- <span>Execute the script.</span><pre><code>$ bash lab_5.sh
- </code></pre>
- </li>
- <li><span>Single line comments begin with </span><code>#</code><span>. Append the following lines to </span><code>lab_5.sh</code><span>.</span><pre><code># Adding comments that do nothing
- echo "Testing single line comments"
- </code></pre>
- <span>Execute the script to see what happens.</span></li>
- <li><span>You can use multi line comments. The format is to start with a colon </span><code>:</code><span> followed by the comments enclosed in single quotes </span><code>'</code><span>. For example, append the following to </span><code>lab_5.sh</code><span>.</span><pre><code>: '
- This is a multi line comment
- Nothing happens in this section
- '
- echo "Back to executable commands"
- </code></pre>
- <span>Execute the script to see what happens.</span></li>
- <li><span>Double brackets are used to do arithmetic tasks. For example, append the following to </span><code>lab_5.sh</code><pre><code># Add two numeric values
- ((sum = 12 + 24))
-
- # Print the sum
- echo $sum
- </code></pre>
- </li>
- <li><span>Get user input with the </span><code>read</code><span> command. This is normally used in combination with echo to print a prompt to the user. Append the following to </span><code>lab_5.sh</code><span>.</span><pre><code>echo "What is your favorite fruit?"
- read fruit
- echo "Hey! I like $fruit too."
- </code></pre>
- </li>
- </ul><h3 id="Task-2---Bash-loops-and-conditions" data-id="Task-2---Bash-loops-and-conditions"><a class="anchor hidden-xs" href="#Task-2---Bash-loops-and-conditions" title="Task-2---Bash-loops-and-conditions"><span class="octicon octicon-link"></span></a><span>Task 2 - Bash loops and conditions</span></h3><ul>
- <li>
- <p><span>Create a simple </span><strong><span>while</span></strong><span> loop. Save the following script as </span><code>while_loop.sh</code><span>.</span></p>
- <pre><code>#!/bin/bash
-
- counter=1
- while [ $counter -le 10 ]
- do
- echo $counter
- ((counter++))
- done
- echo All done
- </code></pre>
- <blockquote>
- <p><code>-le</code><span> is the same as </span><code><=</code><span>.</span></p>
- </blockquote>
- </li>
- <li>
- <p><span>Create an </span><strong><span>until</span></strong><span> loop. The until loop will execute the commands within it until the condition becomes true. Save the following script as </span><code>until_loop.sh</code><span>.</span></p>
- <pre><code>#!/bin/bash
-
- counter=1
- until [ $counter -gt 10 ]
- do
- echo $counter
- ((counter++))
- done
- echo All done
- </code></pre>
- <blockquote>
- <p><code>-gt</code><span> is the same as </span><code>></code><span>.</span></p>
- </blockquote>
- </li>
- <li>
- <p><span>Create a simple </span><strong><span>for</span></strong><span> loop that iterates through the item in a list and prints each of them. Save the following script as </span><code>for_loop.sh</code><span>.</span></p>
- <pre><code>#!/bin/bash
-
- names='Liliya Peter Emili'
- for name in $names
- do
- echo $name
- done
- echo All done
- </code></pre>
- </li>
- <li>
- <p><span>Bash </span><code>for</code><span> loop can be written in “C-Style”. For example save the following script as </span><code>uptime.sh</code><span>.</span></p>
- <pre><code>#!/bin/bash
-
- # Loop of ten iterations to print system uptime every 2 seconds.
- for ((i = 1 ; i <= 10 ; i++)); do
-
- echo -e "$i.\t"$(uptime)
- sleep 2
- done
- </code></pre>
- <p><span>Execute the script and analyze the output.</span></p>
- </li>
- <li>
- <p><span>The </span><strong><span>break</span></strong><span> statement tells bash to exit the loop. An example is shown in </span><code>break.sh</code><span> below.</span></p>
- <pre><code>#!/bin/bash
-
- counter=1
- while [ $counter -le 10 ]
- do
- if [ $counter -eq 5 ]
- then
- echo Script encountered the value $counter
- break
- fi
- echo $counter
- ((counter++))
- done
- echo All done
- </code></pre>
- <blockquote>
- <p><code>-eq</code><span> is the same as </span><code>==</code><span>.</span></p>
- </blockquote>
- </li>
- <li>
- <p><span>The </span><strong><span>continue</span></strong><span> statement skips the cuttent iteration of the loop. Save the following as </span><code>continue.sh</code><span> and run it.</span></p>
- <pre><code>#!/bin/bash
-
- counter=0
- while [ $counter -lt 10 ]
- do
- ((counter++))
- if [ $counter -eq 6 ]
- then
- echo Number 6 encountered, skipping to the next iteration
- continue
- fi
- echo $counter
- done
- echo All done
- </code></pre>
- <blockquote>
- <p><code>-lt</code><span> is the same as </span><code><</code><span>.</span></p>
- </blockquote>
- </li>
- </ul><h3 id="Task-3---If-statements" data-id="Task-3---If-statements"><a class="anchor hidden-xs" href="#Task-3---If-statements" title="Task-3---If-statements"><span class="octicon octicon-link"></span></a><span>Task 3 - If statements</span></h3><ul>
- <li>
- <p><span>If statements allow us to make decisions in our script. This is usually utilized with a comparison operator. Save the following as </span><code>if_statement.sh</code><span>.</span></p>
- <pre><code>#!/bin/bash
-
- echo -n "Enter the number: "
- read number
- if [ $number -gt 100 ]
- then
- echo That\'s a large number.
- elif [ $number -gt 50 ]
- then
- echo Not so much.
- else
- echo The number is way too small.
- fi
- </code></pre>
- </li>
- </ul><h3 id="Task-4---Bash-functions" data-id="Task-4---Bash-functions"><a class="anchor hidden-xs" href="#Task-4---Bash-functions" title="Task-4---Bash-functions"><span class="octicon octicon-link"></span></a><span>Task 4 - Bash functions</span></h3><ul>
- <li>
- <p><span>Create a simple function</span></p>
- <pre><code>$ fun () { echo "This is a function"; echo; }
- </code></pre>
- </li>
- <li>
- <p><span>To view the content of all functions defined in the shell</span></p>
- <pre><code>$ declare -f
- </code></pre>
- </li>
- <li>
- <p><span>To list all functions by its name</span></p>
- <pre><code>$ declare -F
- </code></pre>
- </li>
- <li>
- <p><span>To view the content of the one your function</span></p>
- <pre><code>$ declare -f fun
- </code></pre>
- </li>
- <li>
- <p><span>To remove the function</span></p>
- <pre><code>$ unset fun
- </code></pre>
- </li>
- <li>
- <p><span>Now lets create a script with a 2 functions inside it</span></p>
- <pre><code>$ vim funky.sh
- </code></pre>
- </li>
- <li>
- <p><span>Inside vim type the following</span></p>
- <pre><code>#!/bin/bash
-
- JUST_A_SECOND=3
- funky ()
- { # This is about as simple as functions get.
-
- echo "This is a funky function."
- echo "Now exiting funky function."
- } # Function declaration must precede call
-
- fun ()
- { # A somewhat more complex function.
- i=0
- REPEATS=30
- echo
- echo "And now the fun really begins."
- echo
- sleep $JUST_A_SECOND
- while [ $i -lt $REPEATS ] #use as (<,>,=) or (-lt, -gt, -eq)
- do
- echo "----------FUNCTIONS---------->"
- echo "<------------ARE-------------"
- echo "<------------FUN------------>"
- echo
- let "i+=1"
- done
- }
-
- add_fun()
- {
- # A function just to add numbers
- echo $((2+2))
- }
- #Now, call the functions
- funky
- fun
- echo The return value of add_fun is: $(add_fun)
- echo exit $? #check your exit status of the last function/command: if 0-success, otherwise is not
- </code></pre>
- </li>
- <li>
- <p><span>Run the script</span></p>
- <pre><code>$ bash funky.sh
- </code></pre>
- </li>
- <li>
- <p><span>Notice how the functions are only available within the one shell (once you exit it is gone for the parent shell)</span></p>
- <pre><code>$ declare -F
- </code></pre>
- </li>
- </ul><h2 id="Exercise-2---Working-with-files-and-directories" data-id="Exercise-2---Working-with-files-and-directories"><a class="anchor hidden-xs" href="#Exercise-2---Working-with-files-and-directories" title="Exercise-2---Working-with-files-and-directories"><span class="octicon octicon-link"></span></a><span>Exercise 2 - Working with files and directories</span></h2><h3 id="Task-1---File-and-directory-test-operators" data-id="Task-1---File-and-directory-test-operators"><a class="anchor hidden-xs" href="#Task-1---File-and-directory-test-operators" title="Task-1---File-and-directory-test-operators"><span class="octicon octicon-link"></span></a><span>Task 1 - File and directory test operators</span></h3><p><span>There are several options in bash to check the type of file you are interacting with. In many cases, the options are also used to check for the existence of a specified file or directory. The example below shows the options that can be used.</span></p><ul>
- <li><span>Create a script </span><code>file_checker.sh</code><span> and add the following code:</span><pre><code>#!/bin/bash
-
- if [[ $# -le 0 ]]
- then
- echo "You did not pass any files as arguments to the script."
- echo "Usage:" "$0" "my-file-1 my-file-2"
- exit
- fi
-
- for arg in "$@"
- do
- # Does it actually exist?
- if [[ ! -e "$arg" ]]
- then
- echo "* Skipping ${arg}"
- continue
- fi
-
- # Is it a regular file?
- if [ -f "$arg" ]
- then
- echo "* $arg is a regular file!"
- else
- echo "* $arg is not a regular file!"
- fi
-
- [ -b "$arg" ] && echo "* $arg is a block device."
- [ -d "$arg" ] && echo "* $arg is a directory."
- [ ! -d "$arg" ] && echo "* $arg is not a directory."
-
- [ -x "$arg" ] && echo "* $arg is executable."
- [ ! -x "$arg" ] && echo "* $arg is not executable."
-
- [[ -h "$arg" ]] && echo "* $arg is a symbolic link."
- [ ! -h "$arg" ] && echo "* $arg is not a symbolic link."
-
- [[ -s "$arg" ]] && echo "* $arg has nonzero size."
- [ ! -s "$arg" ] && echo "* $arg has zero size."
-
- [[ -r "$arg" && -d "$arg" ]] && echo "* $arg is a readable directory."
- [[ -r "$arg" && -f "$arg" ]] && echo "* $arg is a readable regular file."
- done
- </code></pre>
- </li>
- <li><span>Run the script and specify the files you want to check as arguments.</span><pre><code># bash file_checker.sh /bin/i386 /etc/passwd
- </code></pre>
- <span>You should get output similar to the following:</span><pre><code>* /bin/i386 is a regular file!
- * /bin/i386 is not a directory.
- * /bin/i386 is executable.
- * /bin/i386 is a symbolic link.
- * /bin/i386 has nonzero size.
- * /bin/i386 is a readable regular file.
- * /etc/passwd is a regular file!
- * /etc/passwd is not a directory.
- * /etc/passwd is not executable.
- * /etc/passwd is not a symbolic link.
- * /etc/passwd has nonzero size.
- * /etc/passwd is a readable regular file.
- </code></pre>
- </li>
- </ul><h3 id="Task-2---Directory-and-file-manipulation" data-id="Task-2---Directory-and-file-manipulation"><a class="anchor hidden-xs" href="#Task-2---Directory-and-file-manipulation" title="Task-2---Directory-and-file-manipulation"><span class="octicon octicon-link"></span></a><span>Task 2 - Directory and file manipulation</span></h3><ul>
- <li>
- <p><span>You can create a new directory in bash with the </span><code>mkdir</code><span> command. Save the following script as </span><code>mkdir_bash.sh</code><span>.</span></p>
- <pre><code>#!/bin/bash
- echo "Enter directory name"
- read newdir
- `mkdir $newdir`
- </code></pre>
- </li>
- <li>
- <p><span>You can check for the existence of a directory before proceeding to create it. Update </span><code>mkdir_bash.sh</code><span> to look like the script shown below.</span></p>
- <pre><code>#!/bin/bash
- echo "Enter directory name"
- read newdir
- if [ -d "$newdir" ]
- then
- echo "Directory exist"
- else
- `mkdir $newdir`
- echo "Directory created"
- fi
- </code></pre>
- </li>
- <li>
- <p><span>Create a bash script to read every line of a specified file. The file name is passed as a command line argument. Save the following script as </span><code>file_reader.sh</code><span>.</span></p>
- <pre><code>#!/bin/bash
-
- file=$1
-
- if [[ "$file" == "" || (! -f "$file") ]]
- then
- echo Using standard input!
- file="/dev/stdin"
- fi
-
- while read -r line
- do
- echo "$line"
- done < "${file}"
- </code></pre>
- <blockquote>
- <p><span>The script reads the first value passed as a command line argument, represented by $1. If a text file is passed, the script will read and output each line of text.</span><br>
- <span>If no command line argument is passed or if the file does not exist, standard input (/dev/stdin) is used instead. This will prompt you to enter text and will output to the terminal screen what is received as input. To signal the end of your stdin input type CTRL+D</span></p>
- </blockquote>
- <p><span>Use this script to read </span><code>/etc/passwd</code><span>.</span></p>
- <pre><code>$ bash file_reader.sh /etc/passwd
- </code></pre>
- </li>
- <li>
- <p><span>The Internal Field Separator (IFS) is used to recognize word boundaries. The default value for IFS consists of whitespace characters. Whitespace characters are space, tab and newline. Add the following script to the file </span><code>ifs_test.sh</code><span>.</span></p>
- <pre><code>#!/bin/bash
-
- mystring="foo:bar baz rab"
- for word in $mystring; do
- echo "Word: $word"
- done
- </code></pre>
- <p><span>Run the script.</span></p>
- </li>
- <li>
- <p><span>The default value for the IFS can be changed. Modify </span><code>ifs_test.sh</code><span> to contain the following.</span></p>
- <pre><code>#!/bin/bash
-
- IFS=:
- mystring="foo:bar baz rab"
- for word in $mystring; do
- echo "Word: $word"
- done
- </code></pre>
- </li>
- <li>
- <p><span>Let’s do this on a larger scale. Read /etc/passwd word by word while using </span><code>:</code><span> as the IFS. Save the following as </span><code>ifs_word.sh</code><span>.</span></p>
- <pre><code>#!/bin/bash
-
- if [[ $# -le 0 ]]
- then
- echo "You did not pass any files as arguments to the script."
- echo "Usage:" "$0" "my-file"
- exit
- fi
-
- IFS=:
- file=$1
-
- if [ ! -f "$file" ]
- then
- echo "File does not exist!"
- fi
-
- for word in $(cat "${file}")
- do
- echo "$word"
- done
- </code></pre>
- <p><span>Run the script specifying </span><code>/etc/passwd</code><span> as an argument.</span></p>
- <pre><code>$ bash ifs_word.sh /etc/passwd
- </code></pre>
- </li>
- </ul><h3 id="Task-3---Jump-directories" data-id="Task-3---Jump-directories"><a class="anchor hidden-xs" href="#Task-3---Jump-directories" title="Task-3---Jump-directories"><span class="octicon octicon-link"></span></a><span>Task 3 - Jump directories</span></h3><p><span>Sometimes it is difficult to navigate directories with the possibly infinite number of parent directories we need to provide. For example </span><code>cd ../../../../../</code><span>. Let’s create a script that will help us jump to a specified directory without executing </span><code>cd ../</code><span>.</span></p><ul>
- <li><span>Create the script </span><code>jump_dir.sh</code><span>.</span><pre><code># !/bin/bash
-
- # A simple bash script to move up to desired directory level directly
-
- function jump()
- {
- # original value of Internal Field Separator
- OLDIFS=$IFS
-
- # setting field separator to "/"
- IFS=/
-
- # converting working path into array of directories in path
- # eg. /my/path/is/like/this
- # into [, my, path, is, like, this]
- path_arr=($PWD)
-
- # setting IFS to original value
- IFS=$OLDIFS
-
- local pos=-1
-
- # ${path_arr[@]} gives all the values in path_arr
- for dir in "${path_arr[@]}"
- do
- # find the number of directories to move up to
- # reach at target directory
- pos=$[$pos+1]
- if [ "$1" = "$dir" ];then
-
- # length of the path_arr
- dir_in_path=${#path_arr[@]}
-
- #current working directory
- cwd=$PWD
- limit=$[$dir_in_path-$pos-1]
- for ((i=0; i<limit; i++))
- do
- cwd=$cwd/..
- done
- cd $cwd
- break
- fi
- done
- }
- </code></pre>
- </li>
- <li><span>Make the script executable</span><pre><code>$ chmod +x jump_dir.sh
- </code></pre>
- </li>
- <li><span>Add it to the .bashrc file to make it available on every terminal session.</span><pre><code>echo "source ~/jump_dir.sh">> ~/.bashrc
- </code></pre>
- </li>
- <li><span>Open a new terminal and try jumping.</span><pre><code>$ jump directory_name
- </code></pre>
- </li>
- </ul><h2 id="Exercise-3---Hash-tables-and-more-bash-usage" data-id="Exercise-3---Hash-tables-and-more-bash-usage"><a class="anchor hidden-xs" href="#Exercise-3---Hash-tables-and-more-bash-usage" title="Exercise-3---Hash-tables-and-more-bash-usage"><span class="octicon octicon-link"></span></a><span>Exercise 3 - Hash tables and more bash usage</span></h2><h3 id="Task-1---Hash-tables-in-bash" data-id="Task-1---Hash-tables-in-bash"><a class="anchor hidden-xs" href="#Task-1---Hash-tables-in-bash" title="Task-1---Hash-tables-in-bash"><span class="octicon octicon-link"></span></a><span>Task 1 - Hash tables in bash</span></h3><p><span>A dictionary, or a hashmap, or an associative array is a data structure used to store a collection of things. A dictionary consists of a collection of key-value pairs. Each key is mapped to its associated value.</span></p><ul>
- <li><span>To declare a dictionary variable in bash, use the </span><code>declare</code><span> statement with the </span><code>-A</code><span> option which means associative array. For example:</span><pre><code>$ declare -A newDictionary
- </code></pre>
- </li>
- <li><span>We have declared a variable called </span><code>newDictionary</code><span>. The following syntax can be used to add key-value pairs to the dictionary:</span><pre><code>$ newDictionary[key]=value
- </code></pre>
- </li>
- <li><span>Let’s add a key-value pair to the dictionary using the syntax above:</span><pre><code>$ newDictionary[1]=SNA
- $ newDictionary[2]=IML
- </code></pre>
- </li>
- <li><span>To retrive the value of a dictionary key, we have to add </span><code>$</code><span> with braces </span><code>{}</code><span> to the dictionary variable we defined.</span><pre><code>$ echo ${newDictionary[1]}
- </code></pre>
- </li>
- <li><span>To update the value of a key, we simply overwrite the existing value by writing to the key again. For example, to update </span><code>newDictionary[1]</code><span>, we do the following:</span><pre><code>$ newDictionary[1]=NEWSNA
- </code></pre>
- <span>Retrieve the value of they key </span><code>[1]</code><span> to verify the update.</span><pre><code>$ echo ${newDictionary[1]}
- NEWSNA
- </code></pre>
- </li>
- <li><span>Use the </span><code>unset</code><span> command to remove a key-value pair from the dictionary.</span><pre><code>$ unset newDictionary[1]
- </code></pre>
- <span>Verify that the pair has been removed from the dictionary.</span><pre><code>$ echo ${newDictionary[1]}
- </code></pre>
- </li>
- <li><span>You can iterate through the dictionary by creating a </span><code>for</code><span> loop. An example is shown in the script below:</span><pre><code>#!/bin/bash
- declare -A newDictionary
- newDictionary[1]=SNA
- newDictionary[2]=IML
- newDictionary[3]=SSN
- for key in "${!newDictionary[@]}"; do
- echo "$key ${newDictionary[$key]}"
- done
- </code></pre>
- <span>You should get an output similar to the following when you run the script:</span><pre><code>3 SSN
- 2 IML
- 1 SNA
- </code></pre>
- </li>
- <li><span>You can also declare and instantiate a dictionary in one line.</span><pre><code>$ declare -A innoCourses=([1]=SNA [2]=IML [3]=SSN)
- </code></pre>
- <span>Check the content of the dictionary.</span><pre><code>echo ${innoCourses[3]}
- </code></pre>
- </li>
- </ul><h3 id="Task-2---Use-sed-in-bash" data-id="Task-2---Use-sed-in-bash"><a class="anchor hidden-xs" href="#Task-2---Use-sed-in-bash" title="Task-2---Use-sed-in-bash"><span class="octicon octicon-link"></span></a><span>Task 2 - Use sed in bash</span></h3><ul>
- <li><span>Use sed to strip all HTML tags in a HTML page. Save the following code as </span><code>sed_bash.sh</code><span>.</span><pre><code>#!/bin/bash
-
- strip-tags ()
- {
- sed -e 's/<[^>]*.//g' -
- }
- curl https://example.com/ --silent | strip-tags
- </code></pre>
- <span>Run the bash script and analyse the output. There is no HTML tag in the results.</span></li>
- </ul><h3 id="Task-3---Execute-Python-commands-in-bash" data-id="Task-3---Execute-Python-commands-in-bash"><a class="anchor hidden-xs" href="#Task-3---Execute-Python-commands-in-bash" title="Task-3---Execute-Python-commands-in-bash"><span class="octicon octicon-link"></span></a><span>Task 3 - Execute Python commands in bash</span></h3><ul>
- <li><span>Python can run one-liners from an operating system command line using option </span><code>-c</code><span>. An example is shown with the command below:</span><pre><code>$ python3 -c "a = 2; b = 4; sum = a + b; print('Sum =', sum)"
- or
- $ python -c "a = 2; b = 4; sum = a + b; print('Sum =', sum)"
- </code></pre>
- <span>The following bash script executes the python command above.</span><pre><code>#!/bin/bash
-
- python3 -c "a = 2; b = 4; sum = a + b; print('Sum =', sum)"
- </code></pre>
- </li>
- <li><span>Alternatively, you scan split your python code into multi-lines by declaring a variable in the following fashion:</span><pre><code>#!/bin/bash
-
- py_script="
- a = 2
- b = 4
- sum = a + b
- print('Sum =', sum)
- "
-
- python3 -c "$py_script"
- </code></pre>
- </li>
- </ul><h2 id="Exercise-4---Debugging-bash-scripts" data-id="Exercise-4---Debugging-bash-scripts"><a class="anchor hidden-xs" href="#Exercise-4---Debugging-bash-scripts" title="Exercise-4---Debugging-bash-scripts"><span class="octicon octicon-link"></span></a><span>Exercise 4 - Debugging bash scripts</span></h2><h3 id="Task-1---Command-exit-code" data-id="Task-1---Command-exit-code"><a class="anchor hidden-xs" href="#Task-1---Command-exit-code" title="Task-1---Command-exit-code"><span class="octicon octicon-link"></span></a><span>Task 1 - Command exit code</span></h3><p><span>You can verify whether a bash command executed successfully by viewing the exit status code of the command. The exit status of the previously executed command is stored in the </span><code>$?</code><span> variable. A successful command returns a </span><code>0</code><span>, while an unsuccessful one returns a non-zero value that usually can be interpreted as an error code.</span></p><ul>
- <li><span>Run the command </span><code>$ ls -lah</code><span>.</span></li>
- <li><span>View the exit status of the previous command with </span><code>$ echo "$?"</code><span>.</span></li>
- <li><span>Now run a command that will fail. For example: </span><code>$ ls -lah /directorythatdoesnotexist</code></li>
- <li><span>Run </span><code>$ echo "$?"</code><span> again to view the exit status. You should get a value that is not </span><code>0</code><span>.</span></li>
- </ul><h3 id="Task-2---Using-set--xe" data-id="Task-2---Using-set--xe"><a class="anchor hidden-xs" href="#Task-2---Using-set--xe" title="Task-2---Using-set--xe"><span class="octicon octicon-link"></span></a><span>Task 2 - Using </span><code>set -xe</code></h3><p><span>When there is an error that stops the execution of a bash script, the bash interpreter usually displays the line number that triggered the error. However, in some cases, it might be necessary to trace the flow of execution of the script. This provides more insight into the conditions that are met, and the state of the loops.</span></p><ul>
- <li><span>The </span><code>set</code><span> command is used to set or unset shell options or positional parameters.</span></li>
- <li><span>We can use the </span><code>set -e</code><span> option to exit the bash script if any command or statement generates a non-zero exit code. This is defined at the start of the script and it applies globally to all commands in the script.</span></li>
- <li><span>Additionally, we can also use the </span><code>set -x</code><span> option to display commands and arguments before they are executed. With this option, we can see every line of command that is executing in the script.</span></li>
- <li><span>The </span><code>set -e</code><span> option and </span><code>-x</code><span> options can be combined to become useful debugging tools. The option </span><code>-e</code><span> exits the script as soon as an error is encountered, and the option </span><code>-x</code><span> shows the command that was running when the error was encountered.</span></li>
- <li><span>Create a bash script </span><code>loop_debug.sh</code><span> and add the following to it:</span><pre><code>#!/bin/bash
-
- set -xe
-
- # This script prints all user profiles.
-
- FILE=".bashrc" # File containing user profile,
- #+ was ".profile" in original script.
-
- for home in `awk -F: '{print $6}' /etc/passwd`
- do
- [ -d "$home" ] || continue # If no home directory, go to next.
- [ -r "$home" ] || continue # If not readable, go to next.
- (cd $home; [ -e $FILE ] && less $FILE)
- done
-
- exit 0
- </code></pre>
- </li>
- <li><span>Run the script and analyze the output. Did the script stop prematurely?</span></li>
- <li><span>Remove the option </span><code>-e</code><span> and run the script again. Did you notice any difference? Why is it different?</span></li>
- <li><span>Now completely remove </span><code>set -xe</code><span> to see how the program executes without these options.</span></li>
- </ul><h2 id="Questions-to-answer" data-id="Questions-to-answer"><a class="anchor hidden-xs" href="#Questions-to-answer" title="Questions-to-answer"><span class="octicon octicon-link"></span></a><span>Questions to answer</span></h2><blockquote>
- <ul>
- <li><span>Upload the shell script files to moodle.</span></li>
- <li><span>Test every feature in your script and show screenshots of the test in your report.</span></li>
- </ul>
- </blockquote><ol>
- <li>
- <p><span>Write a bash script that displays the following details of the logged-in user from the environment variables:</span></p>
- <ul>
- <li><span>Login username</span></li>
- <li><span>Home directory</span></li>
- <li><span>Shell</span></li>
- <li><span>The hostname of the system</span></li>
- <li><span>The script should extract the IP address of the system from the </span><code>ifconfig</code><span> or </span><code>ip</code><span> command. Save the IP address to the </span><code>ipaddress</code><span> variable and display it as output.</span></li>
- </ul>
- <p><span>Sample output:</span></p>
- <pre><code>Username: user1
- Home Directory: /home/user1
- Shell: /bin/bash
- Hostname: ubuntuvm
- IP address: 10.1.1.1
- </code></pre>
- </li>
- <li>
- <p><span>Backups are important in system administration. Create a script that will backup your home directory.</span></p>
- <ul>
- <li><span>The backup file should be compressed to </span><code>tar.gz</code><span>.</span></li>
- <li><span>All files and directory permissions should be preserved in the backup.</span></li>
- <li><span>The backup destination directory is </span><code>/var/backups/</code></li>
- <li><span>The script should create the destination directory if it doesn’t already exist.</span></li>
- <li><span>The backup file name should take the format </span><code>home_backup_month_day_year_hour_minute_second.tar.gz</code><span>.</span><br>
- <span>For example </span><code>home_backup_Feb_18_2023_02_30_02.tar.gz</code></li>
- </ul>
- <blockquote>
- <p><span>A typical real life scenario is keeping backups of websites. Administrators are usually interested in backing up </span><code>/var/www/html</code><span>.</span></p>
- </blockquote>
- </li>
- <li>
- <p><span>Write a bash script that checks various artifacts on the system. The script mainly checks for system information, and OS components. Your script should do the following:</span></p>
- <ul>
- <li><span>Print the OS kernel name and kernel version.</span></li>
- <li><span>Print the system architecture.</span></li>
- <li><span>Print all currently logged in users (show the date or time which the users logged in, and show the command line of the users’ current process).</span></li>
- <li><span>Verify that EFI is enabled and print the relevant output.</span></li>
- <li><span>List all connected block devices (</span><strong><span>Bonus:</span></strong><span> Identify the devices that have the GPT partition by adding an </span><code>*</code><span> to them in the output).</span></li>
- <li><span>List the first boot device on your system. This should be done according to the boot order in the NVRAM.</span></li>
- </ul>
- <blockquote>
- <p><span>Ensure that the output of your script is neatly formatted and easy to read.</span><br>
- <span>Bonus points if you create and use at least three functions.</span></p>
- </blockquote>
- </li>
- </ol><h3 id="Bonus" data-id="Bonus"><a class="anchor hidden-xs" href="#Bonus" title="Bonus"><span class="octicon octicon-link"></span></a><span>Bonus</span></h3><ol start="4">
- <li><span>Write a bash script that scans the entire system for files that contain the string “/bin/bash”. The script should print only the matches that the currently logged in user has execute permission on.</span></li>
- </ol></div>
- <div class="ui-toc dropup unselectable hidden-print" style="display:none;">
- <div class="pull-right dropdown">
- <a id="tocLabel" class="ui-toc-label btn btn-default" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" title="Table of content">
- <i class="fa fa-bars"></i>
- </a>
- <ul id="ui-toc" class="ui-toc-dropdown dropdown-menu" aria-labelledby="tocLabel">
- <div class="toc"><ul class="nav">
- <li><a href="#Lab-5-Bash-scripting" title="Lab 5: Bash scripting">Lab 5: Bash scripting</a><ul class="nav">
- <li><a href="#Exercise-1---Bash-basics" title="Exercise 1 - Bash basics">Exercise 1 - Bash basics</a><ul class="nav">
- <li><a href="#Task-1---Bash-scripting-basics" title="Task 1 - Bash scripting basics">Task 1 - Bash scripting basics</a></li>
- <li><a href="#Task-2---Bash-loops-and-conditions" title="Task 2 - Bash loops and conditions">Task 2 - Bash loops and conditions</a></li>
- <li><a href="#Task-3---If-statements" title="Task 3 - If statements">Task 3 - If statements</a></li>
- <li><a href="#Task-4---Bash-functions" title="Task 4 - Bash functions">Task 4 - Bash functions</a></li>
- </ul>
- </li>
- <li><a href="#Exercise-2---Working-with-files-and-directories" title="Exercise 2 - Working with files and directories">Exercise 2 - Working with files and directories</a><ul class="nav">
- <li><a href="#Task-1---File-and-directory-test-operators" title="Task 1 - File and directory test operators">Task 1 - File and directory test operators</a></li>
- <li><a href="#Task-2---Directory-and-file-manipulation" title="Task 2 - Directory and file manipulation">Task 2 - Directory and file manipulation</a></li>
- <li><a href="#Task-3---Jump-directories" title="Task 3 - Jump directories">Task 3 - Jump directories</a></li>
- </ul>
- </li>
- <li><a href="#Exercise-3---Hash-tables-and-more-bash-usage" title="Exercise 3 - Hash tables and more bash usage">Exercise 3 - Hash tables and more bash usage</a><ul class="nav">
- <li><a href="#Task-1---Hash-tables-in-bash" title="Task 1 - Hash tables in bash">Task 1 - Hash tables in bash</a></li>
- <li><a href="#Task-2---Use-sed-in-bash" title="Task 2 - Use sed in bash">Task 2 - Use sed in bash</a></li>
- <li><a href="#Task-3---Execute-Python-commands-in-bash" title="Task 3 - Execute Python commands in bash">Task 3 - Execute Python commands in bash</a></li>
- </ul>
- </li>
- <li><a href="#Exercise-4---Debugging-bash-scripts" title="Exercise 4 - Debugging bash scripts">Exercise 4 - Debugging bash scripts</a><ul class="nav">
- <li><a href="#Task-1---Command-exit-code" title="Task 1 - Command exit code">Task 1 - Command exit code</a></li>
- <li><a href="#Task-2---Using-set--xe" title="Task 2 - Using set -xe">Task 2 - Using set -xe</a></li>
- </ul>
- </li>
- <li><a href="#Questions-to-answer" title="Questions to answer">Questions to answer</a><ul class="nav">
- <li><a href="#Bonus" title="Bonus">Bonus</a></li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- </div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
- </ul>
- </div>
- </div>
- <div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;" null null>
- <div class="toc"><ul class="nav">
- <li><a href="#Lab-5-Bash-scripting" title="Lab 5: Bash scripting">Lab 5: Bash scripting</a><ul class="nav">
- <li><a href="#Exercise-1---Bash-basics" title="Exercise 1 - Bash basics">Exercise 1 - Bash basics</a><ul class="nav">
- <li><a href="#Task-1---Bash-scripting-basics" title="Task 1 - Bash scripting basics">Task 1 - Bash scripting basics</a></li>
- <li><a href="#Task-2---Bash-loops-and-conditions" title="Task 2 - Bash loops and conditions">Task 2 - Bash loops and conditions</a></li>
- <li><a href="#Task-3---If-statements" title="Task 3 - If statements">Task 3 - If statements</a></li>
- <li><a href="#Task-4---Bash-functions" title="Task 4 - Bash functions">Task 4 - Bash functions</a></li>
- </ul>
- </li>
- <li><a href="#Exercise-2---Working-with-files-and-directories" title="Exercise 2 - Working with files and directories">Exercise 2 - Working with files and directories</a><ul class="nav">
- <li><a href="#Task-1---File-and-directory-test-operators" title="Task 1 - File and directory test operators">Task 1 - File and directory test operators</a></li>
- <li><a href="#Task-2---Directory-and-file-manipulation" title="Task 2 - Directory and file manipulation">Task 2 - Directory and file manipulation</a></li>
- <li><a href="#Task-3---Jump-directories" title="Task 3 - Jump directories">Task 3 - Jump directories</a></li>
- </ul>
- </li>
- <li><a href="#Exercise-3---Hash-tables-and-more-bash-usage" title="Exercise 3 - Hash tables and more bash usage">Exercise 3 - Hash tables and more bash usage</a><ul class="nav">
- <li><a href="#Task-1---Hash-tables-in-bash" title="Task 1 - Hash tables in bash">Task 1 - Hash tables in bash</a></li>
- <li><a href="#Task-2---Use-sed-in-bash" title="Task 2 - Use sed in bash">Task 2 - Use sed in bash</a></li>
- <li><a href="#Task-3---Execute-Python-commands-in-bash" title="Task 3 - Execute Python commands in bash">Task 3 - Execute Python commands in bash</a></li>
- </ul>
- </li>
- <li><a href="#Exercise-4---Debugging-bash-scripts" title="Exercise 4 - Debugging bash scripts">Exercise 4 - Debugging bash scripts</a><ul class="nav">
- <li><a href="#Task-1---Command-exit-code" title="Task 1 - Command exit code">Task 1 - Command exit code</a></li>
- <li><a href="#Task-2---Using-set--xe" title="Task 2 - Using set -xe">Task 2 - Using set -xe</a></li>
- </ul>
- </li>
- <li><a href="#Questions-to-answer" title="Questions to answer">Questions to answer</a><ul class="nav">
- <li><a href="#Bonus" title="Bonus">Bonus</a></li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- </div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
- </div>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
- <script>
- var markdown = $(".markdown-body");
- //smooth all hash trigger scrolling
- function smoothHashScroll() {
- var hashElements = $("a[href^='#']").toArray();
- for (var i = 0; i < hashElements.length; i++) {
- var element = hashElements[i];
- var $element = $(element);
- var hash = element.hash;
- if (hash) {
- $element.on('click', function (e) {
- // store hash
- var hash = this.hash;
- if ($(hash).length <= 0) return;
- // prevent default anchor click behavior
- e.preventDefault();
- // animate
- $('body, html').stop(true, true).animate({
- scrollTop: $(hash).offset().top
- }, 100, "linear", function () {
- // when done, add hash to url
- // (default click behaviour)
- window.location.hash = hash;
- });
- });
- }
- }
- }
-
- smoothHashScroll();
- var toc = $('.ui-toc');
- var tocAffix = $('.ui-affix-toc');
- var tocDropdown = $('.ui-toc-dropdown');
- //toc
- tocDropdown.click(function (e) {
- e.stopPropagation();
- });
-
- var enoughForAffixToc = true;
-
- function generateScrollspy() {
- $(document.body).scrollspy({
- target: ''
- });
- $(document.body).scrollspy('refresh');
- if (enoughForAffixToc) {
- toc.hide();
- tocAffix.show();
- } else {
- tocAffix.hide();
- toc.show();
- }
- $(document.body).scroll();
- }
-
- function windowResize() {
- //toc right
- var paddingRight = parseFloat(markdown.css('padding-right'));
- var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
- toc.css('right', right + 'px');
- //affix toc left
- var newbool;
- var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
- //for ipad or wider device
- if (rightMargin >= 133) {
- newbool = true;
- var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
- var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
- tocAffix.css('left', left + 'px');
- } else {
- newbool = false;
- }
- if (newbool != enoughForAffixToc) {
- enoughForAffixToc = newbool;
- generateScrollspy();
- }
- }
- $(window).resize(function () {
- windowResize();
- });
- $(document).ready(function () {
- windowResize();
- generateScrollspy();
- });
-
- //remove hash
- function removeHash() {
- window.location.hash = '';
- }
-
- var backtotop = $('.back-to-top');
- var gotobottom = $('.go-to-bottom');
-
- backtotop.click(function (e) {
- e.preventDefault();
- e.stopPropagation();
- if (scrollToTop)
- scrollToTop();
- removeHash();
- });
- gotobottom.click(function (e) {
- e.preventDefault();
- e.stopPropagation();
- if (scrollToBottom)
- scrollToBottom();
- removeHash();
- });
-
- var toggle = $('.expand-toggle');
- var tocExpand = false;
-
- checkExpandToggle();
- toggle.click(function (e) {
- e.preventDefault();
- e.stopPropagation();
- tocExpand = !tocExpand;
- checkExpandToggle();
- })
-
- function checkExpandToggle () {
- var toc = $('.ui-toc-dropdown .toc');
- var toggle = $('.expand-toggle');
- if (!tocExpand) {
- toc.removeClass('expand');
- toggle.text('Expand all');
- } else {
- toc.addClass('expand');
- toggle.text('Collapse all');
- }
- }
-
- function scrollToTop() {
- $('body, html').stop(true, true).animate({
- scrollTop: 0
- }, 100, "linear");
- }
-
- function scrollToBottom() {
- $('body, html').stop(true, true).animate({
- scrollTop: $(document.body)[0].scrollHeight
- }, 100, "linear");
- }
- </script>
- </body>
-
- </html>
|