Q2.2 编写并执行脚本
问题:编写两个bash函数marco和polo执行下面的操作:每当你执行marco时,将当前的工作目录以某种形式保存;当你执行polo时,无论当前处于什么目录下,都切换到执行marco的目录(即在任意目录下执行polo即切换到marco保存的目录)。
Step 1 编写脚本marco.sh
保存形式一:将当前目录保存至文件
#!/bin/bash
marco(){
echo "$(pwd)">$HOME/marco_history.log
echo "save pwd $(pwd)"
}
polo(){
cd "$(cat "$HOME/marco_history.log")"
}
保存形式二:将当前目录保存至临时环境变量
marco(){
export MARCO=$(pwd)
echo "save pwd $(pwd)
}
polo(){
cd "$MARCO"
}
tip:Shell中我们使用$(CMD)
获得命令的输出
Step 2 执行脚本
~/missing % source marco.sh # 通过source加载函数
~/missing % marco
save pwd /Users/Owner/missing
~/missing % cd
~ % polo
~/missing %
参考资料:MIT-Missing-Semester > Shell Scripting > Exercises 2
Q2.3 编写一个脚本执行另一个脚本
问题:假设你有一个命令,它很少出错。为了调试它,你需要花费大量时间重现错误并捕获它的输出。编写一个脚本,运行如下脚本直到它出错,将标准输出和标准错误流记录到文件,并在最后输出所有内容。加分点:报告脚本出错前运行了多少次。
#!/user/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"
tips:
$(())
RANDOM % 100
if [[]]; then
fi
Step1 编写脚本
使用while循环
count=1
while true
do
./buggy.sh 2>out.log
if [[ $? -ne 0 ]]; then
echo "failed after $count times"
cat out.log
break
fi
((count++))
done
使用for循环
for ((count=1;;count++))
do
./buggy.sh 2> out.log
if [[ $? -ne 0 ]]; then
echo "failed after $count times"
cat out.log
break
echo "$count try"
fi
done
使用until循环
#!/usr/bin/env bash
count=0
until [[ "$?" -ne 0 ]];
do
count=$((count+1))
./random.sh 2> out.txt
done
echo "found error after $count runs"
cat out.txt
Step2 执行脚本
~/missing % vim
~/missing % ./debug_until.sh
zsh: permission denied: ./debug_until.sh
~/missing % chmod 777 debug_until.sh
~/missing % ./debug_until.sh
found error after 1 runs
./debug_until.sh: line 6: ./random.sh: Permission denied
~/missing % chmod 777 random.sh
~/missing % ./debug_until.sh
Everything went according to plan
Everything went according to plan
Something went wrong
found error after 2 runs
The error was using magic numbers
~/missing %
参考资料:MIT-Missing-Semester > Shell Scripting > Exercises 3
Q2.4 查找文件并压缩
Q: 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
).
Step 1 创建所需文件
mkdir html_root
cd html_root
touch {1..10}.html
mkdir html
cd html
touch xxxx.html
Step 2 执行find命令
#for MacOS
find html_root -name "*.html" -print0 | xargs -0 tar vcf
#for Linux
find . -type f -name "*.html" | xargs -d '\n' tar -cvzf
tips
find
’s -exec
can be very powerful for performing operations over the files we are searching for. However, if we want to do something with all the files, like creating a zip file.
As we have seen so far commands will take inut 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 argument. For exemple ls | xargs rm
will delete the files in the current directory.
xargs
extended arguments- construst argument list(s) and execute utility
options/flags
for MacOS -0
Change xarges to expext NUL (\0
) characters as separators, instead of spaces and newlines.This is expected to be used in concert with the -print
function in find.
for Linux -d
delim分隔符,默认的xargs分隔符是回车,argument的分隔符是空格,这里修改的是xargs的分隔符
find
PRIMARIES
-print0
This primary alwaysevaluates to true. It prints the pathname of the current file to standard output, followed by an ASCII NUL character (character code 0).
tar
- manipulate tape archives 用于备份文件
-c
Create a new archive containing the sprecified items. The long option form is –create
-t
, --list
List archive contents to stdout.
-x
, --extract
Extract to disk from the archive.
-v
, --verbose
Produce vebose output.
-z
, --gunzip
, --gzip
Compress the resulting archive with gzip.
-f <file>
, --file <file>
Read the archive from or write the archive to the specified file.
# Creat a gzipped archive:
tar czvf target.tar.gz file1 file2 file3
# Extract a gzipped archive in the current directory:
tar xzvf source.tar.gz
# List the contents of a tar file:
tar tzvf source.tar
Q2.5
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 -mmin -60 -print0 | xarges -0 ls -lt | head -10
tips
find -mmin [-|+]n
True if the difference between this file last modification time and the time find was started, round up to the next full minute, is more than n (+n), less than n (-n), or exactly n minutes ago.
head
- display first lines of a file
-n
, --lines
= count Print count lines of each of the specified files.