You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
</code></pre><br><h2id=shell-scripting><aclass=headerhref=#shell-scripting>Shell Scripting</a></h2><blockquote><p><imgalt=infosrc=./images/info.svg> Use a temporary working directory before attempting the exercises. You can delete such practice directories afterwards.</blockquote><p><strong>1)</strong> What's wrong with the script shown below? Also, will the error go away if you use <code>bash try.sh</code> instead?<p><code>!#</code> should be <code>#!</code>. If you get confused which one should be used, remember that shebang is a <strong>comment</strong> that is treated specially at the start of the script. And no, the error won't go away if you call the script using the <code>bash</code> command.<pre><codeclass=language-bash>$ printf ' \n!#/bin/bash\n\necho hello\n' > try.sh
1250
+
$ chmod +x try.sh
1251
+
$ ./try.sh
1252
+
./try.sh: line 2: !#/bin/bash: No such file or directory
</code></pre><p><strong>2)</strong> Will the command shown below work? If so, what would be the output?<p>Yes, it will work. <code>echo hello</code> is being passed as the script to be executed by the <code>bash</code> command.<pre><codeclass=language-bash>$ echo echo hello | bash
1260
+
hello
1261
+
</code></pre><p><strong>3)</strong> When would you <code>source</code> a script instead of using <code>bash</code> or creating an executable using shebang?<p>Using <code>source</code> to execute scripts helps when you want to affect the current working environment.<p><strong>4)</strong> How would you display the contents of a variable with <code>shake</code> appended?<pre><codeclass=language-bash>$ fruit='banana'
1262
+
1263
+
$ echo "${fruit}shake"
1264
+
bananashake
1265
+
</code></pre><p><strong>5)</strong> What changes would you make to the code shown below to get the expected output?<pre><codeclass=language-bash># default behavior
1266
+
$ n=100
1267
+
$ n+=100
1268
+
$ echo "$n"
1269
+
100100
1270
+
1271
+
# expected output
1272
+
$ declare -i n=100
1273
+
$ n+=100
1274
+
$ echo "$n"
1275
+
200
1276
+
</code></pre><p><strong>6)</strong> Is the following code valid? If so, what would be the output of the <code>echo</code> command?<p>Yes, it is valid. Array index can be arbitrarily used, they do not have to be contiguous.<pre><codeclass=language-bash>$ declare -a colors
1277
+
$ colors[3]='green'
1278
+
$ colors[1]='blue'
1279
+
1280
+
$ echo "${colors[@]}"
1281
+
blue green
1282
+
</code></pre><p><strong>7)</strong> How would you get the last three characters of a variable's contents?<pre><codeclass=language-bash>$ fruit='banana'
1283
+
1284
+
$ echo "${fruit: -3}"
1285
+
ana
1286
+
</code></pre><p><strong>8)</strong> Will the second <code>echo</code> command give an error? If not, what will be the output?<p>No error. It will give the length of the element at index <code>0</code>.<pre><codeclass=language-bash>$ fruits=('apple' 'fig' 'mango')
1287
+
$ echo "${#fruits[@]}"
1288
+
3
1289
+
1290
+
$ echo "${#fruits}"
1291
+
5
1292
+
</code></pre><p><strong>9)</strong> For the given array, use parameter expansion to remove characters until first/last space.<pre><codeclass=language-bash>$ colors=('green' 'dark brown' 'deep sky blue white')
1293
+
1294
+
# remove till first space
1295
+
$ printf '%s\n' "${colors[@]#* }"
1296
+
green
1297
+
brown
1298
+
sky blue white
1299
+
1300
+
# remove till last space
1301
+
$ printf '%s\n' "${colors[@]##* }"
1302
+
green
1303
+
brown
1304
+
white
1305
+
</code></pre><p><strong>10)</strong> Use parameter expansion to get the expected outputs shown below.<pre><codeclass=language-bash>$ ip='apple:banana:cherry:dragon'
1306
+
1307
+
$ echo "${ip%:*}"
1308
+
apple:banana:cherry
1309
+
1310
+
$ echo "${ip%%:*}"
1311
+
apple
1312
+
</code></pre><p><strong>11)</strong> Is it possible to achieve the expected outputs shown below using parameter expansion? If so, how?<p>Yes it is possible. For the second and third cases, <code>extglob</code> has to be enabled.<pre><codeclass=language-bash>$ ip='apple:banana:cherry:dragon'
1313
+
1314
+
$ echo "${ip/:*:/ 42 }"
1315
+
apple 42 dragon
1316
+
1317
+
$ shopt -s extglob
1318
+
$ echo "${ip/#+([^:])/fig}"
1319
+
fig:banana:cherry:dragon
1320
+
1321
+
$ echo "${ip/%+([^:])/end}"
1322
+
apple:banana:cherry:end
1323
+
</code></pre><p><strong>12)</strong> For the given input, change case as per the expected outputs shown below.<pre><codeclass=language-bash>$ ip='This is a Sample STRING'
1324
+
1325
+
$ echo "${ip^^}"
1326
+
THIS IS A SAMPLE STRING
1327
+
1328
+
$ echo "${ip,,}"
1329
+
this is a sample string
1330
+
1331
+
$ echo "${ip~~}"
1332
+
tHIS IS A sAMPLE string
1333
+
</code></pre><p><strong>13)</strong> Why does the conditional expression shown below fail?<pre><codeclass=language-bash>$ touch ip.txt
1334
+
$ [[-f ip.txt]] && echo 'file exists'
1335
+
[[-f: command not found
1336
+
1337
+
# need to use space after [[ and before ]]
1338
+
$ [[ -f ip.txt ]] && echo 'file exists'
1339
+
file exists
1340
+
</code></pre><p><strong>14)</strong> What is the difference between <code>==</code> and <code>=~</code> string comparison operators?<ul><li><code>s1 = s2</code> or <code>s1 == s2</code> checks if two strings are equal <ul><li>unquoted portions of <code>s2</code> will be treated as a wildcard while testing against <code>s1</code></ul><li><code>s1 =~ s2</code> checks if <code>s1</code> matches the POSIX extended regular expression provided by <code>s2</code></ul><p><strong>15)</strong> Why does the conditional expression used below show <code>failed</code> both times? Modify the expressions such that the first one correctly says <code>matched</code> instead of <code>failed</code>.<p>Quoted portions will be treated as literal strings. Wildcards should be unquoted.<pre><codeclass=language-bash>$ f1='1234.txt'
</code></pre><p><strong>16)</strong> Extract the digits that follow a <code>:</code> character for the given variable contents.<pre><codeclass=language-bash>$ item='chocolate:50'
</code></pre><p><strong>17)</strong> Modify the expression shown below to correctly report <code>true</code> instead of <code>false</code>.<pre><codeclass=language-bash>$ num=12345
1361
+
$ [[ $num > 3 ]] && echo 'true' || echo 'false'
1362
+
false
1363
+
1364
+
# corrected code
1365
+
$ [[ $num -gt 3 ]] && echo 'true' || echo 'false'
1366
+
true
1367
+
1368
+
# alternate solutions
1369
+
$ (( num > 3 )) && echo 'true' || echo 'false'
1370
+
</code></pre><p><strong>18)</strong> Write a shell script named <code>array.sh</code> that accepts array input from the user followed by another input as index. Display the corresponding value at that index. Couple of examples are shown below.<pre><codeclass=language-bash>$ cat array.sh
1371
+
read -p 'enter array elements: ' -a arr
1372
+
read -p 'enter array index: ' idx
1373
+
echo "element at index '$idx' is: ${arr[$idx]}"
1374
+
1375
+
$ bash array.sh
1376
+
enter array elements: apple banana cherry
1377
+
enter array index: 1
1378
+
element at index '1' is: banana
1379
+
1380
+
$ bash array.sh
1381
+
enter array elements: dragon unicorn centaur
1382
+
enter array index: -1
1383
+
element at index '-1' is: centaur
1384
+
</code></pre><p><strong>19)</strong> Write a shell script named <code>case.sh</code> that accepts exactly two command line arguments. The first argument can be <code>lower</code>, <code>upper</code> or <code>swap</code> and this should be used to transform the contents of the second argument. Examples script invocations are shown below, including what should happen if the command line arguments do not meet the script expectations.<pre><codeclass=language-bash>$ cat case.sh
1385
+
if (( $# != 2 )) ; then
1386
+
echo 'Error! Two arguments expected.' 1>&2
1387
+
exit 1
1388
+
else
1389
+
if [[ $1 == 'upper' ]] ; then
1390
+
echo "${2^^}"
1391
+
elif [[ $1 == 'lower' ]] ; then
1392
+
echo "${2,,}"
1393
+
elif [[ $1 == 'swap' ]] ; then
1394
+
echo "${2~~}"
1395
+
else
1396
+
echo "Error! '$1' command not recognized." 1>&2
1397
+
exit 1
1398
+
fi
1399
+
fi
1400
+
1401
+
$ chmod +x case.sh
1402
+
1403
+
$ ./case.sh upper 'how are you?'
1404
+
HOW ARE YOU?
1405
+
1406
+
$ ./case.sh lower PineAPPLE
1407
+
pineapple
1408
+
1409
+
$ ./case.sh swap 'HeLlo WoRlD'
1410
+
hElLO wOrLd
1411
+
1412
+
$ ./case.sh lower
1413
+
Error! Two arguments expected.
1414
+
$ echo $?
1415
+
1
1416
+
1417
+
$ ./case.sh upper apple fig
1418
+
Error! Two arguments expected.
1419
+
1420
+
$ ./case.sh lowercase DRAGON
1421
+
Error! 'lowercase' command not recognized.
1422
+
$ echo $?
1423
+
1
1424
+
1425
+
$ ./case.sh apple lower 2> /dev/null
1426
+
$ echo $?
1427
+
1
1428
+
</code></pre><p><strong>20)</strong> Write a shell script named <code>loop.sh</code> that displays the number of lines for each of the files passed as command line arguments.<pre><codeclass=language-bash>$ printf 'apple\nbanana\ncherry\n' > items_1.txt
echo "number of lines in '$file' is:" $(wc -l < "$file")
1434
+
done
1435
+
1436
+
$ bash loop.sh items_1.txt
1437
+
number of lines in 'items_1.txt' is: 3
1438
+
1439
+
$ bash loop.sh items_1.txt items_2.txt
1440
+
number of lines in 'items_1.txt' is: 3
1441
+
number of lines in 'items_2.txt' is: 5
1442
+
</code></pre><p><strong>21)</strong> Write a shell script named <code>read_file.sh</code> that reads a file line by line to be passed as argument to the <code>paste -sd,</code> command. Can you also write a solution using the <code>xargs</code> command instead of a script?<pre><codeclass=language-bash>$ printf 'apple\nbanana\ncherry\n' > items_1.txt
# note that -n1 is not necessary here due to how paste works for multiple files
1456
+
# but -n1 is necessary to be equivalent to the shell script shown above
1457
+
$ xargs -a list.txt -d'\n' -n1 paste -sd,
1458
+
apple,banana,cherry
1459
+
dragon,owl,unicorn,troll,centaur
1460
+
</code></pre><p><strong>22)</strong> Write a function named <code>add_path</code> which prefixes the path of the current working directory to the arguments it receives and displays the results. Examples are shown below.<pre><codeclass=language-bash>$ add_path() { echo "${@/#/$PWD/}" ; }
</code></pre><p><strong>23)</strong> What do the options <code>bash -x</code> and <code>bash -v</code> do?<blockquote><p><code>-x</code><p>Print commands and their arguments as they are executed.<p><code>-v</code><p>Print shell input lines as they are read.</blockquote><p><strong>24)</strong> What is <code>shellcheck</code> and when would you use it?<p><ahref=https://www.shellcheck.net/>shellcheck</a> is a static analysis tool that gives warnings and suggestions for scripts.<p>From <code>man shellcheck</code>:<blockquote><p>ShellCheck is a static analysis and linting tool for sh/bash scripts. It’s mainly focused on handling typical beginner and intermediate level syntax errors and pitfalls where the shell just gives a cryptic error message or strange behavior, but it also reports on a few more advanced issues where corner cases can cause delayed failures.</blockquote><br><h2id=shell-customization><aclass=headerhref=#shell-customization>Shell Customization</a></h2><p><strong>1)</strong> Which command would you use to display the name and value of all or specific environment variables?<pre><codeclass=language-bash>$ whatis printenv
1474
+
printenv (1) - print all or part of environment
1475
+
</code></pre><p><strong>2)</strong> If you add an alias for an already existing command (<code>ls</code> for example), how would you invoke the original command instead of the alias?<p>By prefixing <code>\</code> or using the <code>command</code> builtin. For example, <code>\ls</code> or <code>command ls</code>.<p><strong>3)</strong> Why doesn't the alias shown below work? What would you use instead?<p>You cannot pass arguments to aliases, need to use functions instead.<pre><codeclass=language-bash># doesn't work as expected
1476
+
$ alias ext='echo "${1##*.}"'
1477
+
$ ext ip.txt
1478
+
ip.txt
1479
+
1480
+
# expected output
1481
+
$ ext() { echo "${1##*.}" ; }
1482
+
$ ext ip.txt
1483
+
txt
1484
+
$ ext scores.csv
1485
+
csv
1486
+
$ ext file.txt.txt
1487
+
txt
1488
+
</code></pre><p><strong>4)</strong> How would you remove a particular alias/function definition for the current shell session?<pre><codeclass=language-bash>$ alias hw='echo hello world'
1489
+
$ hw
1490
+
hello world
1491
+
$ unalias hw
1492
+
$ hw
1493
+
hw: command not found
1494
+
1495
+
$ hw() { echo hello there ; }
1496
+
$ hw
1497
+
hello there
1498
+
$ unset -f hw
1499
+
$ hw
1500
+
hw: command not found
1501
+
</code></pre><p><strong>5)</strong> Write an alias and a function to display the contents of <code>PATH</code> environment variable on separate lines by changing <code>:</code> to the newline character. Sample output is shown below.<pre><codeclass=language-bash>$ echo "$PATH"
1502
+
/usr/local/bin:/usr/bin:/bin:/usr/games
1503
+
1504
+
# alias
1505
+
$ alias a_p='echo "$PATH" | tr ":" "\n"'
1506
+
$ a_p
1507
+
/usr/local/bin
1508
+
/usr/bin
1509
+
/bin
1510
+
/usr/games
1511
+
1512
+
# function
1513
+
$ f_p() { echo "${PATH//:/$'\n'}" ; }
1514
+
$ f_p
1515
+
/usr/local/bin
1516
+
/usr/bin
1517
+
/bin
1518
+
/usr/games
1519
+
</code></pre><p><strong>6)</strong> Will a login shell read and execute <code>~/.bashrc</code> automatically?<p>No. From <code>info bash</code>:<blockquote><p>When an interactive shell that is not a login shell is started, Bash reads and executes commands from '~/.bashrc', if that file exists.</blockquote><p>See also <ahref=https://unix.stackexchange.com/q/257571/109046>unix.stackexchange: why does bashrc check whether the current shell is interactive?</a><p><strong>7)</strong> What should be the value assigned to <code>HISTSIZE</code> if you wish to have unlimited history entries?<p>Any negative number.<blockquote><p><code>HISTSIZE</code><p>The maximum number of commands to remember on the history list. If the value is 0, commands are not saved in the history list. Numeric values less than zero result in every command being saved on the history list (there is no limit). The shell sets the default value to 500 after reading any startup files.</blockquote><p><strong>8)</strong> What does the binding <code>set completion-ignore-case on</code> do?<blockquote><p><code>completion-ignore-case</code><p>If set to <code>on</code>, Readline performs filename matching and completion in a case-insensitive fashion. The default value is <code>off</code>.</blockquote><p><strong>9)</strong> Which shortcut helps you interactively search command history?<blockquote><p>To search backward in the history for a particular string, type <code>C-r</code>. Typing <code>C-s</code> searches forward through the history.</blockquote><p><strong>10)</strong> What do the shortcuts <code>Alt+b</code> and <code>Alt+f</code> do?<blockquote><p><code>forward-word (M-f)</code><p>Move forward to the end of the next word. Words are composed of letters and digits.<p><code>backward-word (M-b)</code><p>Move back to the start of the current or previous word. Words are composed of letters and digits.</blockquote><p><strong>11)</strong> Are there differences between the <code>Ctrl+l</code> shortcut and the <code>clear</code> command?<p><code>Ctrl+l</code> retains whatever is typed so far and doesn't try to remove the scrollback buffer altogether. You can use the <code>clear</code> command for that purpose.<p><strong>12)</strong> Which shortcut will you use to delete characters before the cursor till the start of the line?<blockquote><p><code>unix-line-discard (C-u)</code><p>Kill backward from the cursor to the beginning of the current line.</blockquote><p><strong>13)</strong> What do the shortcuts <code>Alt+t</code> and <code>Ctrl+t</code> do?<blockquote><p><code>transpose-chars (C-t)</code><p>Drag the character before the cursor forward over the character at the cursor, moving the cursor forward as well. If the insertion point is at the end of the line, then this transposes the last two characters of the line. Negative arguments have no effect.<p><code>transpose-words (M-t)</code><p>Drag the word before point past the word after point, moving point past that word as well. If the insertion point is at the end of the line, this transposes the last two words on the line.</blockquote><p><strong>14)</strong> Is there any difference between <code>Shift+Insert</code> and <code>Shift+Ctrl+v</code> shortcuts?<ul><li><code>Shift+Ctrl+v</code> pastes clipboard contents<li><code>Shift+Insert</code> pastes the last highlighted portion (not necessarily the clipboard contents)</ul></main><navaria-label="Page navigation"class=nav-wrapper><aaria-label="Previous chapter"class="mobile-nav-chapters previous"title="Previous chapter"aria-keyshortcuts=Lefthref=shell-customization.htmlrel=prev><iclass="fa fa-angle-left"></i></a><divstyle="clear: both"></div></nav></div></div><navaria-label="Page navigation"class=nav-wide-wrapper><aaria-label="Previous chapter"class="nav-chapters previous"title="Previous chapter"aria-keyshortcuts=Lefthref=shell-customization.htmlrel=prev><iclass="fa fa-angle-left"></i></a></nav></div><script>window.playground_copyable=true;</script><scriptcharset=utf-8src=elasticlunr.min.js></script><scriptcharset=utf-8src=mark.min.js></script><scriptcharset=utf-8src=searcher.js></script><scriptcharset=utf-8src=clipboard.min.js></script><scriptcharset=utf-8src=highlight.js></script><scriptcharset=utf-8src=book.js></script><scriptsrc=sidebar.js></script>
0 commit comments