Command: ls args

  1. Read man ls and write an ls command that lists files in the following manner
  • Includes all files, including hidden files
  • Sizes are listed in human readable format (e.g. 454M instead of 454279954)
  • Files are ordered by recency (时效性)
  • Output is colorized
1
2
3
4
5
6
$ ls -ahltc
-rw-r--r-- 1 user group 1.1M Jan 14 09:53 baz
drwxr-xr-x 5 user group 160 Jan 14 09:53 .
-rw-r--r-- 1 user group 514 Jan 14 06:42 bar
-rw-r--r-- 1 user group 106M Jan 13 12:12 foo
drwx------+ 47 user group 1.5K Jan 12 18:08 ..

-h: use unit suffixes: B, KB, MB…

-l: list files in long format

-t: sorted by descending time modified

-c: use time when file status was last changed for sorting or printing.

In order to show . and .. :

-a: include dir entries whose names begin with a dot ('.')

Bash functions

  1. Write bash functions marco and polo that do the following. Whenever you execute marco the current working directory should be saved in some manner, then when you execute polo, no matter what directory you are in, polo should cd you back to the directory where you executed marco. For ease of debugging you can write the code in a file marco.sh and (re)load the definitions to your shell by executing source marco.sh.

The whole processing is:

1
2
3
4
5
6
7
8
(base) zoriswangdeMacBook-Pro:xv6Core zoriswang$ vim marco.sh
(base) zoriswangdeMacBook-Pro:xv6Core zoriswang$ source marco.sh
(base) zoriswangdeMacBook-Pro:xv6Core zoriswang$ marco test
In /Users/zoriswang/Desktop/GitHub/xv6Core/test
(base) zoriswangdeMacBook-Pro:test zoriswang$ vim polo.sh
(base) zoriswangdeMacBook-Pro:test zoriswang$ source polo.sh
(base) zoriswangdeMacBook-Pro:test zoriswang$ polo
By using polo, now we are in /Users/zoriswang/Desktop/GitHub/xv6Core
1
2
3
4
5
6
7
8
9
10
11
// For simplify back to historical command, use `history` or Ctrl+R to check former command.
$ history 1 | grep vim
120 vim test.cpp
126 vim test.cpp
128 vim test.cpp
130 vim test.cpp
166 vim ~/.bash_profile
402 vim semester
448 cd test && vim mcd.sh
515 vim marco.sh
518 vim polo.sh

But I find a nice shell named fish , by using this, you could find your files more quickly. Such as following shortcutting:

The marco.sh and polo.sh are:

1
2
3
4
5
6
// marco.sh
marco () {
mkdir "$1"
cd "$1"
echo "In $(pwd)"
}
1
2
3
4
5
// polo.sh
polo () {
cd ..
echo "By using polo, now we are in $(pwd)"
}

BASH Redirection

  1. Say you have a command that fails rarely. In order to debug it you need to capture its output but it can be time consuming to get a failure run. Write a bash script that runs the following script until it fails and captures its standard output and error streams to files and prints everything at the end. Bonus points if you can also report how many runs it took for the script to fail.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/usr/bin/env bash

    n=$(( RANDOM % 100 ))

    if [[ n -eq 42 ]]; then
    echo "Something went wrong"
    >&2 echo "The error was using magic numbers"
    exit 1
    fi

    echo "Everything went according to plan"

Let’s firstly check a demo code: (because I don’t understand grep that line’s function)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

echo "Starting program at $(date)" # Date will be substituted

echo "Running program $0 with $# arguments with pid $$"

for file in "$@"; do
grep foobar "$file" 1> /dev/null 2> /dev/null
# When pattern is not found, grep has exit status 1
# We redirect STDOUT and STDERR to a null register since we do not care about them
if [[ $? -ne 0 ]]; then
echo "File $file does not have any foobar, adding one"
echo "# foobar" >> "$file"
fi
done

> /dev/null 2> /dev/null: 将 grep 命令的 STDOUT(1>) 和 STDERR(2>) 都 redirect 到 /dev/null 设备上,表示舍弃。

/dev/null 是特殊的 Linux 虚拟设备,专门用于倾倒不需要的垃圾数据

I find a stupid thing about my code: I always think the scripts only could be run after source and should allocate a specified function to it.

But it could run by add shebang #!/usr/bin/env bash , then use bash xxx.sh to run it is fine…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// use_random.sh
#!/usr/bin/env bash

cnt=0
err=0
while [ true ]; do
bash random.sh 1>>./mid-out.txt 2>>./mid-err.txt
((++cnt))
if [ -s ./mid-err.txt ]; then
break
fi
done
cat ./mid-out.txt ./mid-err.txt
rm ./mid-out.txt ./mid-err.txt
echo "runs $cnt times to throw an error"

find & xargs

  1. Write a command that recursively finds all HTML files in the folder and makes a zip with them. Note that your command should work even if the files have spaces (hint: check -d flag for xargs).

See some xargs examples by tldr xargs:

So we could use find to get all html files as xargs arguments, then executes tar to zip thest input files.

What’s more, let’s check tar usage:

1
2
// use this cmd
$ find ~ -name "*.html" | xargs tar cf 4.tar

List inner files in 4.tar:

1
2
3
4
$ tar tvf 4.tar
-rw-r--r-- 0 zoriswang staff 329 11 22 15:28 Users/zoriswang/.gitbook/versions/3.2.3/node_modules/npm/html/dochead.html
.........
-rw-r--r-- 0 zoriswang staff 961 11 22 15:28 Users/zoriswang/.gitbook/versions/3.2.3/docs/_layouts/website/page.html

Then rm them:

1
2
3
$ find 4.tar | xargs rm
$ find 4.tar
find: 4.tar: No such file or directory

Use scripts to list recently files

  1. (Advanced) Write a command or script to recursively find the most recently modified file in a directory. More generally, can you list all files by recency?
1
2
3
#!/usr/bin/env bash

echo "$(ls -altc $1)"