shell 练习 (lecture 2)

66 阅读2分钟

ls练习

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

答案:

# -a 列出所有文件, 
# -l 列出文件大小、权限等信息
# -h human readable format, 
# -t sorted by [t]ime the file was modified
# -G Enable colorized output
ls -alhtG

shell脚本练习

  • 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.
  • 答案
#!/usr/bin/env bash

marco(){
export EXEC_MARCO_DIR="$(pwd)"
 echo "exec marco shell path is $EXEC_MARCO_DIR"
}

polo(){
 # 注意,[]内的判断条件需要和[]有空格
 if [[ -z "$EXEC_MARCO_DIR" ]];then
     echo "exec_marco_dir is empty" 
 else 
    echo "cd $EXEC_MARCO_DIR"
    cd "$EXEC_MARCO_DIR"
fi
}


  • 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.
#!/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"

答案:

#!/usr/bin/env bash

run_count=0

# clear files
err_log="err.log"
out_log="output.log"
> "$err_log"
> "$out_log"

run(){
 n=$(( RANDOM % 100 ))

 if [[ n -eq 42 ]]; then
    echo "Something went wrong" >> "$out_log"
    >&2 echo "The error was using magic numbers" >> "$err_log"
    # exit 1会直接终止整个脚本的运行
    return 1
 fi

 echo "Everything went according to plan" >> "$out_log"
 return 0
}

while true; do 
  run_count=$(( run_count+1 )) 
  run
  status=$?
  if [[ status -ne 0 ]]; then
    break
  fi
done

echo "it took $run_count times for the script to fail."

find练习

  1. As we covered in the lecture find’s -exec can be very powerful for performing operations over the files we are searching for. However, what if we want to do something with all the files, like creating a zip file? As you have seen so far commands will take input from both arguments and STDIN. When piping commands, we are connecting STDOUT to STDIN, but some commands like tar take inputs from arguments. To bridge this disconnect there’s the xargs command which will execute a command using STDIN as arguments. For example ls | xargs rm will delete the files in the current directory.

    Your task is to 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).

    If you’re on macOS, note that the default BSD find is different from the one included in GNU coreutils. You can use -print0 on find and the -0 flag on xargs. As a macOS user, you should be aware that command-line utilities shipped with macOS may differ from the GNU counterparts; you can install the GNU versions if you like by using brew.

答案:

# -print0: 用 **null 字符**(\0)作为文件名分隔符,以便正确处理文件名中包含空格或其他特殊字符的情况。
# xargs -0:
# 配合 -print0 使用,告诉 xargs 使用 null 字符作为分隔符来处理文件名
# 在 macOS 上,由于默认的 xargs 不支持 -d,所以你需要使用 -0 来正确处理文件名中的空格或特殊字符
find . -name "*.html" -print0 | xargs -0 tar czf my_html.tar.gz
  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?
    答案:
find . -type f -exec ls -lt {} + | head -n 1

参考:missing.csail.mit.edu/2020/shell-…