You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

878 lines
65 KiB

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  7. <meta name="apple-mobile-web-app-capable" content="yes">
  8. <meta name="apple-mobile-web-app-status-bar-style" content="black">
  9. <meta name="mobile-web-app-capable" content="yes">
  10. <title>
  11. Lab 5: Bash scripting - HackMD
  12. </title>
  13. <link rel="icon" type="image/png" href="https://hackmd.io/favicon.png">
  14. <link rel="apple-touch-icon" href="https://hackmd.io/apple-touch-icon.png">
  15. <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" />
  16. <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" />
  17. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
  18. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
  19. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css" integrity="sha256-vtR0hSWRc3Tb26iuN2oZHt3KRUomwTufNIf5/4oeCyg=" crossorigin="anonymous" />
  20. <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" />
  21. <style>
  22. @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}
  23. </style>
  24. <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
  25. <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
  26. <!--[if lt IE 9]>
  27. <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js" integrity="sha256-3Jy/GbSLrg0o9y5Z5n1uw0qxZECH7C6OQpVBgNFYa0g=" crossorigin="anonymous"></script>
  28. <script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js" integrity="sha256-g6iAfvZp+nDQ2TdTR/VVKJf3bGro4ub5fvWSWVRi2NE=" crossorigin="anonymous"></script>
  29. <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>
  30. <![endif]-->
  31. </head>
  32. <body>
  33. <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>
  34. <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>
  35. <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
  36. echo -E "Printing text with newline. This is the default option."
  37. echo -n "What happens when we print text without new line"
  38. echo -e "\nEscaping \t characters \t to print\nnew lines for example"
  39. </code></pre>
  40. <span>Execute the script.</span><pre><code>$ bash lab_5.sh
  41. </code></pre>
  42. </li>
  43. <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
  44. echo "Testing single line comments"
  45. </code></pre>
  46. <span>Execute the script to see what happens.</span></li>
  47. <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>: '
  48. This is a multi line comment
  49. Nothing happens in this section
  50. '
  51. echo "Back to executable commands"
  52. </code></pre>
  53. <span>Execute the script to see what happens.</span></li>
  54. <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
  55. ((sum = 12 + 24))
  56. # Print the sum
  57. echo $sum
  58. </code></pre>
  59. </li>
  60. <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?"
  61. read fruit
  62. echo "Hey! I like $fruit too."
  63. </code></pre>
  64. </li>
  65. </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>
  66. <li>
  67. <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>
  68. <pre><code>#!/bin/bash
  69. counter=1
  70. while [ $counter -le 10 ]
  71. do
  72. echo $counter
  73. ((counter++))
  74. done
  75. echo All done
  76. </code></pre>
  77. <blockquote>
  78. <p><code>-le</code><span> is the same as </span><code>&lt;=</code><span>.</span></p>
  79. </blockquote>
  80. </li>
  81. <li>
  82. <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>
  83. <pre><code>#!/bin/bash
  84. counter=1
  85. until [ $counter -gt 10 ]
  86. do
  87. echo $counter
  88. ((counter++))
  89. done
  90. echo All done
  91. </code></pre>
  92. <blockquote>
  93. <p><code>-gt</code><span> is the same as </span><code>&gt;</code><span>.</span></p>
  94. </blockquote>
  95. </li>
  96. <li>
  97. <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>
  98. <pre><code>#!/bin/bash
  99. names='Liliya Peter Emili'
  100. for name in $names
  101. do
  102. echo $name
  103. done
  104. echo All done
  105. </code></pre>
  106. </li>
  107. <li>
  108. <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>
  109. <pre><code>#!/bin/bash
  110. # Loop of ten iterations to print system uptime every 2 seconds.
  111. for ((i = 1 ; i &lt;= 10 ; i++)); do
  112. echo -e "$i.\t"$(uptime)
  113. sleep 2
  114. done
  115. </code></pre>
  116. <p><span>Execute the script and analyze the output.</span></p>
  117. </li>
  118. <li>
  119. <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>
  120. <pre><code>#!/bin/bash
  121. counter=1
  122. while [ $counter -le 10 ]
  123. do
  124. if [ $counter -eq 5 ]
  125. then
  126. echo Script encountered the value $counter
  127. break
  128. fi
  129. echo $counter
  130. ((counter++))
  131. done
  132. echo All done
  133. </code></pre>
  134. <blockquote>
  135. <p><code>-eq</code><span> is the same as </span><code>==</code><span>.</span></p>
  136. </blockquote>
  137. </li>
  138. <li>
  139. <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>
  140. <pre><code>#!/bin/bash
  141. counter=0
  142. while [ $counter -lt 10 ]
  143. do
  144. ((counter++))
  145. if [ $counter -eq 6 ]
  146. then
  147. echo Number 6 encountered, skipping to the next iteration
  148. continue
  149. fi
  150. echo $counter
  151. done
  152. echo All done
  153. </code></pre>
  154. <blockquote>
  155. <p><code>-lt</code><span> is the same as </span><code>&lt;</code><span>.</span></p>
  156. </blockquote>
  157. </li>
  158. </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>
  159. <li>
  160. <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>
  161. <pre><code>#!/bin/bash
  162. echo -n "Enter the number: "
  163. read number
  164. if [ $number -gt 100 ]
  165. then
  166. echo That\'s a large number.
  167. elif [ $number -gt 50 ]
  168. then
  169. echo Not so much.
  170. else
  171. echo The number is way too small.
  172. fi
  173. </code></pre>
  174. </li>
  175. </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>
  176. <li>
  177. <p><span>Create a simple function</span></p>
  178. <pre><code>$ fun () { echo "This is a function"; echo; }
  179. </code></pre>
  180. </li>
  181. <li>
  182. <p><span>To view the content of all functions defined in the shell</span></p>
  183. <pre><code>$ declare -f
  184. </code></pre>
  185. </li>
  186. <li>
  187. <p><span>To list all functions by its name</span></p>
  188. <pre><code>$ declare -F
  189. </code></pre>
  190. </li>
  191. <li>
  192. <p><span>To view the content of the one your function</span></p>
  193. <pre><code>$ declare -f fun
  194. </code></pre>
  195. </li>
  196. <li>
  197. <p><span>To remove the function</span></p>
  198. <pre><code>$ unset fun
  199. </code></pre>
  200. </li>
  201. <li>
  202. <p><span>Now lets create a script with a 2 functions inside it</span></p>
  203. <pre><code>$ vim funky.sh
  204. </code></pre>
  205. </li>
  206. <li>
  207. <p><span>Inside vim type the following</span></p>
  208. <pre><code>#!/bin/bash
  209. JUST_A_SECOND=3
  210. funky ()
  211. { # This is about as simple as functions get.
  212. echo "This is a funky function."
  213. echo "Now exiting funky function."
  214. } # Function declaration must precede call
  215. fun ()
  216. { # A somewhat more complex function.
  217. i=0
  218. REPEATS=30
  219. echo
  220. echo "And now the fun really begins."
  221. echo
  222. sleep $JUST_A_SECOND
  223. while [ $i -lt $REPEATS ] #use as (&lt;,&gt;,=) or (-lt, -gt, -eq)
  224. do
  225. echo "----------FUNCTIONS----------&gt;"
  226. echo "&lt;------------ARE-------------"
  227. echo "&lt;------------FUN------------&gt;"
  228. echo
  229. let "i+=1"
  230. done
  231. }
  232. add_fun()
  233. {
  234. # A function just to add numbers
  235. echo $((2+2))
  236. }
  237. #Now, call the functions
  238. funky
  239. fun
  240. echo The return value of add_fun is: $(add_fun)
  241. echo exit $? #check your exit status of the last function/command: if 0-success, otherwise is not
  242. </code></pre>
  243. </li>
  244. <li>
  245. <p><span>Run the script</span></p>
  246. <pre><code>$ bash funky.sh
  247. </code></pre>
  248. </li>
  249. <li>
  250. <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>
  251. <pre><code>$ declare -F
  252. </code></pre>
  253. </li>
  254. </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>
  255. <li><span>Create a script </span><code>file_checker.sh</code><span> and add the following code:</span><pre><code>#!/bin/bash
  256. if [[ $# -le 0 ]]
  257. then
  258. echo "You did not pass any files as arguments to the script."
  259. echo "Usage:" "$0" "my-file-1 my-file-2"
  260. exit
  261. fi
  262. for arg in "$@"
  263. do
  264. # Does it actually exist?
  265. if [[ ! -e "$arg" ]]
  266. then
  267. echo "* Skipping ${arg}"
  268. continue
  269. fi
  270. # Is it a regular file?
  271. if [ -f "$arg" ]
  272. then
  273. echo "* $arg is a regular file!"
  274. else
  275. echo "* $arg is not a regular file!"
  276. fi
  277. [ -b "$arg" ] &amp;&amp; echo "* $arg is a block device."
  278. [ -d "$arg" ] &amp;&amp; echo "* $arg is a directory."
  279. [ ! -d "$arg" ] &amp;&amp; echo "* $arg is not a directory."
  280. [ -x "$arg" ] &amp;&amp; echo "* $arg is executable."
  281. [ ! -x "$arg" ] &amp;&amp; echo "* $arg is not executable."
  282. [[ -h "$arg" ]] &amp;&amp; echo "* $arg is a symbolic link."
  283. [ ! -h "$arg" ] &amp;&amp; echo "* $arg is not a symbolic link."
  284. [[ -s "$arg" ]] &amp;&amp; echo "* $arg has nonzero size."
  285. [ ! -s "$arg" ] &amp;&amp; echo "* $arg has zero size."
  286. [[ -r "$arg" &amp;&amp; -d "$arg" ]] &amp;&amp; echo "* $arg is a readable directory."
  287. [[ -r "$arg" &amp;&amp; -f "$arg" ]] &amp;&amp; echo "* $arg is a readable regular file."
  288. done
  289. </code></pre>
  290. </li>
  291. <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
  292. </code></pre>
  293. <span>You should get output similar to the following:</span><pre><code>* /bin/i386 is a regular file!
  294. * /bin/i386 is not a directory.
  295. * /bin/i386 is executable.
  296. * /bin/i386 is a symbolic link.
  297. * /bin/i386 has nonzero size.
  298. * /bin/i386 is a readable regular file.
  299. * /etc/passwd is a regular file!
  300. * /etc/passwd is not a directory.
  301. * /etc/passwd is not executable.
  302. * /etc/passwd is not a symbolic link.
  303. * /etc/passwd has nonzero size.
  304. * /etc/passwd is a readable regular file.
  305. </code></pre>
  306. </li>
  307. </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>
  308. <li>
  309. <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>
  310. <pre><code>#!/bin/bash
  311. echo "Enter directory name"
  312. read newdir
  313. `mkdir $newdir`
  314. </code></pre>
  315. </li>
  316. <li>
  317. <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>
  318. <pre><code>#!/bin/bash
  319. echo "Enter directory name"
  320. read newdir
  321. if [ -d "$newdir" ]
  322. then
  323. echo "Directory exist"
  324. else
  325. `mkdir $newdir`
  326. echo "Directory created"
  327. fi
  328. </code></pre>
  329. </li>
  330. <li>
  331. <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>
  332. <pre><code>#!/bin/bash
  333. file=$1
  334. if [[ "$file" == "" || (! -f "$file") ]]
  335. then
  336. echo Using standard input!
  337. file="/dev/stdin"
  338. fi
  339. while read -r line
  340. do
  341. echo "$line"
  342. done &lt; "${file}"
  343. </code></pre>
  344. <blockquote>
  345. <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>
  346. <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>
  347. </blockquote>
  348. <p><span>Use this script to read </span><code>/etc/passwd</code><span>.</span></p>
  349. <pre><code>$ bash file_reader.sh /etc/passwd
  350. </code></pre>
  351. </li>
  352. <li>
  353. <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>
  354. <pre><code>#!/bin/bash
  355. mystring="foo:bar baz rab"
  356. for word in $mystring; do
  357. echo "Word: $word"
  358. done
  359. </code></pre>
  360. <p><span>Run the script.</span></p>
  361. </li>
  362. <li>
  363. <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>
  364. <pre><code>#!/bin/bash
  365. IFS=:
  366. mystring="foo:bar baz rab"
  367. for word in $mystring; do
  368. echo "Word: $word"
  369. done
  370. </code></pre>
  371. </li>
  372. <li>
  373. <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>
  374. <pre><code>#!/bin/bash
  375. if [[ $# -le 0 ]]
  376. then
  377. echo "You did not pass any files as arguments to the script."
  378. echo "Usage:" "$0" "my-file"
  379. exit
  380. fi
  381. IFS=:
  382. file=$1
  383. if [ ! -f "$file" ]
  384. then
  385. echo "File does not exist!"
  386. fi
  387. for word in $(cat "${file}")
  388. do
  389. echo "$word"
  390. done
  391. </code></pre>
  392. <p><span>Run the script specifying </span><code>/etc/passwd</code><span> as an argument.</span></p>
  393. <pre><code>$ bash ifs_word.sh /etc/passwd
  394. </code></pre>
  395. </li>
  396. </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>
  397. <li><span>Create the script </span><code>jump_dir.sh</code><span>.</span><pre><code># !/bin/bash
  398. # A simple bash script to move up to desired directory level directly
  399. function jump()
  400. {
  401. # original value of Internal Field Separator
  402. OLDIFS=$IFS
  403. # setting field separator to "/"
  404. IFS=/
  405. # converting working path into array of directories in path
  406. # eg. /my/path/is/like/this
  407. # into [, my, path, is, like, this]
  408. path_arr=($PWD)
  409. # setting IFS to original value
  410. IFS=$OLDIFS
  411. local pos=-1
  412. # ${path_arr[@]} gives all the values in path_arr
  413. for dir in "${path_arr[@]}"
  414. do
  415. # find the number of directories to move up to
  416. # reach at target directory
  417. pos=$[$pos+1]
  418. if [ "$1" = "$dir" ];then
  419. # length of the path_arr
  420. dir_in_path=${#path_arr[@]}
  421. #current working directory
  422. cwd=$PWD
  423. limit=$[$dir_in_path-$pos-1]
  424. for ((i=0; i&lt;limit; i++))
  425. do
  426. cwd=$cwd/..
  427. done
  428. cd $cwd
  429. break
  430. fi
  431. done
  432. }
  433. </code></pre>
  434. </li>
  435. <li><span>Make the script executable</span><pre><code>$ chmod +x jump_dir.sh
  436. </code></pre>
  437. </li>
  438. <li><span>Add it to the .bashrc file to make it available on every terminal session.</span><pre><code>echo "source ~/jump_dir.sh"&gt;&gt; ~/.bashrc
  439. </code></pre>
  440. </li>
  441. <li><span>Open a new terminal and try jumping.</span><pre><code>$ jump directory_name
  442. </code></pre>
  443. </li>
  444. </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>
  445. <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
  446. </code></pre>
  447. </li>
  448. <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
  449. </code></pre>
  450. </li>
  451. <li><span>Let’s add a key-value pair to the dictionary using the syntax above:</span><pre><code>$ newDictionary[1]=SNA
  452. $ newDictionary[2]=IML
  453. </code></pre>
  454. </li>
  455. <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]}
  456. </code></pre>
  457. </li>
  458. <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
  459. </code></pre>
  460. <span>Retrieve the value of they key </span><code>[1]</code><span> to verify the update.</span><pre><code>$ echo ${newDictionary[1]}
  461. NEWSNA
  462. </code></pre>
  463. </li>
  464. <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]
  465. </code></pre>
  466. <span>Verify that the pair has been removed from the dictionary.</span><pre><code>$ echo ${newDictionary[1]}
  467. </code></pre>
  468. </li>
  469. <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
  470. declare -A newDictionary
  471. newDictionary[1]=SNA
  472. newDictionary[2]=IML
  473. newDictionary[3]=SSN
  474. for key in "${!newDictionary[@]}"; do
  475. echo "$key ${newDictionary[$key]}"
  476. done
  477. </code></pre>
  478. <span>You should get an output similar to the following when you run the script:</span><pre><code>3 SSN
  479. 2 IML
  480. 1 SNA
  481. </code></pre>
  482. </li>
  483. <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)
  484. </code></pre>
  485. <span>Check the content of the dictionary.</span><pre><code>echo ${innoCourses[3]}
  486. </code></pre>
  487. </li>
  488. </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>
  489. <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
  490. strip-tags ()
  491. {
  492. sed -e 's/&lt;[^&gt;]*.//g' -
  493. }
  494. curl https://example.com/ --silent | strip-tags
  495. </code></pre>
  496. <span>Run the bash script and analyse the output. There is no HTML tag in the results.</span></li>
  497. </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>
  498. <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)"
  499. or
  500. $ python -c "a = 2; b = 4; sum = a + b; print('Sum =', sum)"
  501. </code></pre>
  502. <span>The following bash script executes the python command above.</span><pre><code>#!/bin/bash
  503. python3 -c "a = 2; b = 4; sum = a + b; print('Sum =', sum)"
  504. </code></pre>
  505. </li>
  506. <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
  507. py_script="
  508. a = 2
  509. b = 4
  510. sum = a + b
  511. print('Sum =', sum)
  512. "
  513. python3 -c "$py_script"
  514. </code></pre>
  515. </li>
  516. </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>
  517. <li><span>Run the command </span><code>$ ls -lah</code><span>.</span></li>
  518. <li><span>View the exit status of the previous command with </span><code>$ echo "$?"</code><span>.</span></li>
  519. <li><span>Now run a command that will fail. For example: </span><code>$ ls -lah /directorythatdoesnotexist</code></li>
  520. <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>
  521. </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>
  522. <li><span>The </span><code>set</code><span> command is used to set or unset shell options or positional parameters.</span></li>
  523. <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>
  524. <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>
  525. <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>
  526. <li><span>Create a bash script </span><code>loop_debug.sh</code><span> and add the following to it:</span><pre><code>#!/bin/bash
  527. set -xe
  528. # This script prints all user profiles.
  529. FILE=".bashrc" # File containing user profile,
  530. #+ was ".profile" in original script.
  531. for home in `awk -F: '{print $6}' /etc/passwd`
  532. do
  533. [ -d "$home" ] || continue # If no home directory, go to next.
  534. [ -r "$home" ] || continue # If not readable, go to next.
  535. (cd $home; [ -e $FILE ] &amp;&amp; less $FILE)
  536. done
  537. exit 0
  538. </code></pre>
  539. </li>
  540. <li><span>Run the script and analyze the output. Did the script stop prematurely?</span></li>
  541. <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>
  542. <li><span>Now completely remove </span><code>set -xe</code><span> to see how the program executes without these options.</span></li>
  543. </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>
  544. <ul>
  545. <li><span>Upload the shell script files to moodle.</span></li>
  546. <li><span>Test every feature in your script and show screenshots of the test in your report.</span></li>
  547. </ul>
  548. </blockquote><ol>
  549. <li>
  550. <p><span>Write a bash script that displays the following details of the logged-in user from the environment variables:</span></p>
  551. <ul>
  552. <li><span>Login username</span></li>
  553. <li><span>Home directory</span></li>
  554. <li><span>Shell</span></li>
  555. <li><span>The hostname of the system</span></li>
  556. <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>
  557. </ul>
  558. <p><span>Sample output:</span></p>
  559. <pre><code>Username: user1
  560. Home Directory: /home/user1
  561. Shell: /bin/bash
  562. Hostname: ubuntuvm
  563. IP address: 10.1.1.1
  564. </code></pre>
  565. </li>
  566. <li>
  567. <p><span>Backups are important in system administration. Create a script that will backup your home directory.</span></p>
  568. <ul>
  569. <li><span>The backup file should be compressed to </span><code>tar.gz</code><span>.</span></li>
  570. <li><span>All files and directory permissions should be preserved in the backup.</span></li>
  571. <li><span>The backup destination directory is </span><code>/var/backups/</code></li>
  572. <li><span>The script should create the destination directory if it doesn’t already exist.</span></li>
  573. <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>
  574. <span>For example </span><code>home_backup_Feb_18_2023_02_30_02.tar.gz</code></li>
  575. </ul>
  576. <blockquote>
  577. <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>
  578. </blockquote>
  579. </li>
  580. <li>
  581. <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>
  582. <ul>
  583. <li><span>Print the OS kernel name and kernel version.</span></li>
  584. <li><span>Print the system architecture.</span></li>
  585. <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>
  586. <li><span>Verify that EFI is enabled and print the relevant output.</span></li>
  587. <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>
  588. <li><span>List the first boot device on your system. This should be done according to the boot order in the NVRAM.</span></li>
  589. </ul>
  590. <blockquote>
  591. <p><span>Ensure that the output of your script is neatly formatted and easy to read.</span><br>
  592. <span>Bonus points if you create and use at least three functions.</span></p>
  593. </blockquote>
  594. </li>
  595. </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">
  596. <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>
  597. </ol></div>
  598. <div class="ui-toc dropup unselectable hidden-print" style="display:none;">
  599. <div class="pull-right dropdown">
  600. <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">
  601. <i class="fa fa-bars"></i>
  602. </a>
  603. <ul id="ui-toc" class="ui-toc-dropdown dropdown-menu" aria-labelledby="tocLabel">
  604. <div class="toc"><ul class="nav">
  605. <li><a href="#Lab-5-Bash-scripting" title="Lab 5: Bash scripting">Lab 5: Bash scripting</a><ul class="nav">
  606. <li><a href="#Exercise-1---Bash-basics" title="Exercise 1 - Bash basics">Exercise 1 - Bash basics</a><ul class="nav">
  607. <li><a href="#Task-1---Bash-scripting-basics" title="Task 1 - Bash scripting basics">Task 1 - Bash scripting basics</a></li>
  608. <li><a href="#Task-2---Bash-loops-and-conditions" title="Task 2 - Bash loops and conditions">Task 2 - Bash loops and conditions</a></li>
  609. <li><a href="#Task-3---If-statements" title="Task 3 - If statements">Task 3 - If statements</a></li>
  610. <li><a href="#Task-4---Bash-functions" title="Task 4 - Bash functions">Task 4 - Bash functions</a></li>
  611. </ul>
  612. </li>
  613. <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">
  614. <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>
  615. <li><a href="#Task-2---Directory-and-file-manipulation" title="Task 2 - Directory and file manipulation">Task 2 - Directory and file manipulation</a></li>
  616. <li><a href="#Task-3---Jump-directories" title="Task 3 - Jump directories">Task 3 - Jump directories</a></li>
  617. </ul>
  618. </li>
  619. <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">
  620. <li><a href="#Task-1---Hash-tables-in-bash" title="Task 1 - Hash tables in bash">Task 1 - Hash tables in bash</a></li>
  621. <li><a href="#Task-2---Use-sed-in-bash" title="Task 2 - Use sed in bash">Task 2 - Use sed in bash</a></li>
  622. <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>
  623. </ul>
  624. </li>
  625. <li><a href="#Exercise-4---Debugging-bash-scripts" title="Exercise 4 - Debugging bash scripts">Exercise 4 - Debugging bash scripts</a><ul class="nav">
  626. <li><a href="#Task-1---Command-exit-code" title="Task 1 - Command exit code">Task 1 - Command exit code</a></li>
  627. <li><a href="#Task-2---Using-set--xe" title="Task 2 - Using set -xe">Task 2 - Using set -xe</a></li>
  628. </ul>
  629. </li>
  630. <li><a href="#Questions-to-answer" title="Questions to answer">Questions to answer</a><ul class="nav">
  631. <li><a href="#Bonus" title="Bonus">Bonus</a></li>
  632. </ul>
  633. </li>
  634. </ul>
  635. </li>
  636. </ul>
  637. </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>
  638. </ul>
  639. </div>
  640. </div>
  641. <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>
  642. <div class="toc"><ul class="nav">
  643. <li><a href="#Lab-5-Bash-scripting" title="Lab 5: Bash scripting">Lab 5: Bash scripting</a><ul class="nav">
  644. <li><a href="#Exercise-1---Bash-basics" title="Exercise 1 - Bash basics">Exercise 1 - Bash basics</a><ul class="nav">
  645. <li><a href="#Task-1---Bash-scripting-basics" title="Task 1 - Bash scripting basics">Task 1 - Bash scripting basics</a></li>
  646. <li><a href="#Task-2---Bash-loops-and-conditions" title="Task 2 - Bash loops and conditions">Task 2 - Bash loops and conditions</a></li>
  647. <li><a href="#Task-3---If-statements" title="Task 3 - If statements">Task 3 - If statements</a></li>
  648. <li><a href="#Task-4---Bash-functions" title="Task 4 - Bash functions">Task 4 - Bash functions</a></li>
  649. </ul>
  650. </li>
  651. <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">
  652. <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>
  653. <li><a href="#Task-2---Directory-and-file-manipulation" title="Task 2 - Directory and file manipulation">Task 2 - Directory and file manipulation</a></li>
  654. <li><a href="#Task-3---Jump-directories" title="Task 3 - Jump directories">Task 3 - Jump directories</a></li>
  655. </ul>
  656. </li>
  657. <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">
  658. <li><a href="#Task-1---Hash-tables-in-bash" title="Task 1 - Hash tables in bash">Task 1 - Hash tables in bash</a></li>
  659. <li><a href="#Task-2---Use-sed-in-bash" title="Task 2 - Use sed in bash">Task 2 - Use sed in bash</a></li>
  660. <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>
  661. </ul>
  662. </li>
  663. <li><a href="#Exercise-4---Debugging-bash-scripts" title="Exercise 4 - Debugging bash scripts">Exercise 4 - Debugging bash scripts</a><ul class="nav">
  664. <li><a href="#Task-1---Command-exit-code" title="Task 1 - Command exit code">Task 1 - Command exit code</a></li>
  665. <li><a href="#Task-2---Using-set--xe" title="Task 2 - Using set -xe">Task 2 - Using set -xe</a></li>
  666. </ul>
  667. </li>
  668. <li><a href="#Questions-to-answer" title="Questions to answer">Questions to answer</a><ul class="nav">
  669. <li><a href="#Bonus" title="Bonus">Bonus</a></li>
  670. </ul>
  671. </li>
  672. </ul>
  673. </li>
  674. </ul>
  675. </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>
  676. </div>
  677. <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
  678. <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
  679. <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>
  680. <script>
  681. var markdown = $(".markdown-body");
  682. //smooth all hash trigger scrolling
  683. function smoothHashScroll() {
  684. var hashElements = $("a[href^='#']").toArray();
  685. for (var i = 0; i < hashElements.length; i++) {
  686. var element = hashElements[i];
  687. var $element = $(element);
  688. var hash = element.hash;
  689. if (hash) {
  690. $element.on('click', function (e) {
  691. // store hash
  692. var hash = this.hash;
  693. if ($(hash).length <= 0) return;
  694. // prevent default anchor click behavior
  695. e.preventDefault();
  696. // animate
  697. $('body, html').stop(true, true).animate({
  698. scrollTop: $(hash).offset().top
  699. }, 100, "linear", function () {
  700. // when done, add hash to url
  701. // (default click behaviour)
  702. window.location.hash = hash;
  703. });
  704. });
  705. }
  706. }
  707. }
  708. smoothHashScroll();
  709. var toc = $('.ui-toc');
  710. var tocAffix = $('.ui-affix-toc');
  711. var tocDropdown = $('.ui-toc-dropdown');
  712. //toc
  713. tocDropdown.click(function (e) {
  714. e.stopPropagation();
  715. });
  716. var enoughForAffixToc = true;
  717. function generateScrollspy() {
  718. $(document.body).scrollspy({
  719. target: ''
  720. });
  721. $(document.body).scrollspy('refresh');
  722. if (enoughForAffixToc) {
  723. toc.hide();
  724. tocAffix.show();
  725. } else {
  726. tocAffix.hide();
  727. toc.show();
  728. }
  729. $(document.body).scroll();
  730. }
  731. function windowResize() {
  732. //toc right
  733. var paddingRight = parseFloat(markdown.css('padding-right'));
  734. var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
  735. toc.css('right', right + 'px');
  736. //affix toc left
  737. var newbool;
  738. var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
  739. //for ipad or wider device
  740. if (rightMargin >= 133) {
  741. newbool = true;
  742. var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
  743. var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
  744. tocAffix.css('left', left + 'px');
  745. } else {
  746. newbool = false;
  747. }
  748. if (newbool != enoughForAffixToc) {
  749. enoughForAffixToc = newbool;
  750. generateScrollspy();
  751. }
  752. }
  753. $(window).resize(function () {
  754. windowResize();
  755. });
  756. $(document).ready(function () {
  757. windowResize();
  758. generateScrollspy();
  759. });
  760. //remove hash
  761. function removeHash() {
  762. window.location.hash = '';
  763. }
  764. var backtotop = $('.back-to-top');
  765. var gotobottom = $('.go-to-bottom');
  766. backtotop.click(function (e) {
  767. e.preventDefault();
  768. e.stopPropagation();
  769. if (scrollToTop)
  770. scrollToTop();
  771. removeHash();
  772. });
  773. gotobottom.click(function (e) {
  774. e.preventDefault();
  775. e.stopPropagation();
  776. if (scrollToBottom)
  777. scrollToBottom();
  778. removeHash();
  779. });
  780. var toggle = $('.expand-toggle');
  781. var tocExpand = false;
  782. checkExpandToggle();
  783. toggle.click(function (e) {
  784. e.preventDefault();
  785. e.stopPropagation();
  786. tocExpand = !tocExpand;
  787. checkExpandToggle();
  788. })
  789. function checkExpandToggle () {
  790. var toc = $('.ui-toc-dropdown .toc');
  791. var toggle = $('.expand-toggle');
  792. if (!tocExpand) {
  793. toc.removeClass('expand');
  794. toggle.text('Expand all');
  795. } else {
  796. toc.addClass('expand');
  797. toggle.text('Collapse all');
  798. }
  799. }
  800. function scrollToTop() {
  801. $('body, html').stop(true, true).animate({
  802. scrollTop: 0
  803. }, 100, "linear");
  804. }
  805. function scrollToBottom() {
  806. $('body, html').stop(true, true).animate({
  807. scrollTop: $(document.body)[0].scrollHeight
  808. }, 100, "linear");
  809. }
  810. </script>
  811. </body>
  812. </html>