日期处理脚本与Windows 10上Bash安装指南
1. GNU date的优势
GNU date是一个强大的日期处理工具,安装后,它能轻松处理复杂的日期计算。比如判断某一年是否为闰年,只需使用以下命令:
if [ $( date 12/31/$year +%j ) -eq 366 ]
如果一年的最后一天是该年的第366天,那么这一年就是闰年。此外,GNU date还能处理较早的日期,而标准Unix的date命令以1970年1月1日00:00:00 UTC为“时间零点”,无法处理早于该时间的日期。
2. 查找过去特定日期是星期几
以下是 dayinpast 脚本的代码:
#!/bin/bash
# dayinpast--Given a date, reports what day of the week it was
if [ $# -ne 3 ] ; then
echo "Usage: $(basename $0) mon day year" >&2
echo " with just numerical values (ex: 7 7 1776)" >&2
exit 1
fi
date --version > /dev/null 2>&1 # Discard error, if any.
baddate="$?" # Just look at return code.
if [ ! $baddate ] ; then
date -d $1/$2/$3 +"That was a %A."
else
if [ $2 -lt 10 ] ; then
pattern=" $2[^0-9]"
else
pattern="$2[^0-9]"
fi
dayofweek="$(vncal $1 $3 | grep "$pattern" | cut -c1-2)"
case $dayofweek in
Su ) echo "That was a Sunday."; ;;
Mo ) echo "That was a Monday."; ;;
Tu ) echo "That was a Tuesday."; ;;
We ) echo "That was a Wednesday."; ;;
Th ) echo "That was a Thursday."; ;;
Fr ) echo "That was a Friday."; ;;
Sa ) echo "That was a Saturday."; ;;
esac
fi
exit 0
这个脚本接收三个参数:月份、日期和年份。如果系统支持GNU date,直接使用 date -d 命令输出该日期是星期几;否则,使用 ncal 命令获取该月的日历信息,再通过 grep 和 cut 命令提取出星期几的缩写,最后通过 case 语句将缩写转换为完整的星期名称。
运行示例:
$ dayinpast 7 20 1969
That was a Sunday.
$ dayinpast 6 6 1944
That was a Tuesday.
$ dayinpast 7 4 1776
That was a Thursday.
3. 计算两个日期之间的天数
daysago 脚本用于计算过去某个日期距离今天的天数,代码如下:
#!/bin/bash
# daysago--Given a date in the form month/day/year, calculates how many
# days in the past that was, factoring in leap years, etc.
# If you are on Linux, this should only be 'which date'.
# If you are on OS X, install coreutils with brew or from source for gdate.
date="$(which gdate)"
function daysInMonth
{
case $1 in
1|3|5|7|8|10|12 ) dim=31 ;; # Most common value
4|6|9|11 ) dim=30 ;;
2 ) dim=29 ;; # Depending on whether it's a leap year
* ) dim=-1 ;; # Unknown month
esac
}
function isleap
{
# Returns nonzero value for $leapyear if $1 was a leap year
leapyear=$($date -d 12/31/$1 +%j | grep 366)
}
#######################
#### MAIN BLOCK
#######################
if [ $# -ne 3 ] ; then
echo "Usage: $(basename $0) mon day year"
echo " with just numerical values (ex: 7 7 1776)"
exit 1
fi
$date --version > /dev/null 2>&1 # Discard error, if any.
if [ $? -ne 0 ] ; then
echo "Sorry, but $(basename $0) can't run without GNU date." >&2
exit 1
fi
eval $($date "+thismon=%m;thisday=%d;thisyear=%Y;dayofyear=%j")
startmon=$1; startday=$2; startyear=$3
daysInMonth $startmon # Sets global var dim.
if [ $startday -lt 0 -o $startday -gt $dim ] ; then
echo "Invalid: Month #$startmon only has $dim days." >&2
exit 1
fi
if [ $startmon -eq 2 -a $startday -eq 29 ] ; then
isleap $startyear
if [ -z "$leapyear" ] ; then
echo "Invalid: $startyear wasn't a leap year; February had 28 days." >&2
exit 1
fi
fi
#######################
#### CALCULATING DAYS
#######################
#### DAYS LEFT IN START YEAR
# Calculate the date string format for the specified starting date.
startdatefmt="$startmon/$startday/$startyear"
calculate="$((10#$($date -d "12/31/$startyear" +%j))) \
-$((10#$($date -d $startdatefmt +%j)))"
daysleftinyear=$(( $calculate ))
#### DAYS IN INTERVENING YEARS
daysbetweenyears=0
tempyear=$(( $startyear + 1 ))
while [ $tempyear -lt $thisyear ] ; do
daysbetweenyears=$(($daysbetweenyears + \
$((10#$($date -d "12/31/$tempyear" +%j)))))
tempyear=$(( $tempyear + 1 ))
done
#### DAYS IN CURRENT YEAR
dayofyear=$($date +%j) # That's easy!
#### NOW ADD IT ALL UP
totaldays=$(( $((10#$daysleftinyear)) + \
$((10#$daysbetweenyears)) + \
$((10#$dayofyear)) ))
/bin/echo -n "$totaldays days have elapsed between "
/bin/echo -n "$startmon/$startday/$startyear "
echo "and today, day $dayofyear of $thisyear."
exit 0
该脚本的主要步骤如下:
1. 输入验证 :检查输入的参数是否为三个数值(月份、日期和年份),并验证日期的有效性。
2. 闰年判断 :使用 isleap 函数判断输入年份是否为闰年。
3. 计算天数 :
- 计算起始年份剩余的天数。
- 计算中间年份的总天数。
- 获取当前年份已经过去的天数。
4. 汇总结果 :将上述三个部分的天数相加,得到总天数。
运行示例:
$ daysago 7 20 1969
17106 days have elapsed between 7/20/1969 and today, day 141 of 2016.
$ daysago 6 6 1944
26281 days have elapsed between 6/6/1944 and today, day 141 of 2016.
$ daysago 1 1 2010
2331 days have elapsed between 1/1/2010 and today, day 141 of 2016.
4. 计算距离指定日期的天数
daysuntil 脚本用于计算距离未来某个日期还有多少天,代码如下:
#!/bin/bash
# daysuntil--Basically, this is the daysago script backward, where the
# desired date is set as the current date and the current date is used
# as the basis of the daysago calculation.
# As in the previous script, use 'which gdate' if you are on OS X.
# If you are on Linux, use 'which date'.
date="$(which gdate)"
function daysInMonth
{
case $1 in
1|3|5|7|8|10|12 ) dim=31 ;; # Most common value
4|6|9|11 ) dim=30 ;;
2 ) dim=29 ;; # Depending on whether it's a leap year
* ) dim=-1 ;; # Unknown month
esac
}
function isleap
{
# If specified year is a leap year, returns nonzero value for $leapyear
leapyear=$($date -d 12/31/$1 +%j | grep 366)
}
#######################
#### MAIN BLOCK
#######################
if [ $# -ne 3 ] ; then
echo "Usage: $(basename $0) mon day year"
echo " with just numerical values (ex: 1 1 2020)"
exit 1
fi
$date --version > /dev/null 2>&1 # Discard error, if any.
if [ $? -ne 0 ] ; then
echo "Sorry, but $(basename $0) can't run without GNU date." >&2
exit 1
fi
eval $($date "+thismon=%m;thisday=%d;thisyear=%Y;dayofyear=%j")
endmon=$1; endday=$2; endyear=$3
# Lots of parameter checks needed...
daysInMonth $endmon # Sets $dim variable
if [ $endday -lt 0 -o $endday -gt $dim ] ; then
echo "Invalid: Month #$endmon only has $dim days." >&2
exit 1
fi
if [ $endmon -eq 2 -a $endday -eq 29 ] ; then
isleap $endyear
if [ -z "$leapyear" ] ; then
echo "Invalid: $endyear wasn't a leapyear; February had 28 days." >&2
exit 1
fi
fi
if [ $endyear -lt $thisyear ] ; then
echo "Invalid: $endmon/$endday/$endyear is prior to the current year." >&2
exit 1
fi
if [ $endyear -eq $thisyear -a $endmon -lt $thismon ] ; then
echo "Invalid: $endmon/$endday/$endyear is prior to the current month." >&2
exit 1
fi
if [ $endyear -eq $thisyear -a $endmon -eq $thismon -a $endday -lt $thisday ]
then
echo "Invalid: $endmon/$endday/$endyear is prior to the current date." >&2
exit 1
fi
if [ $endyear -eq $thisyear -a $endmon -eq $thismon -a $endday -eq $thisday ]
then
echo "There are zero days between $endmon/$endday/$endyear and today." >&2
exit 0
fi
#### If we're working with the same year, the calculation is a bit different.
if [ $endyear -eq $thisyear ] ; then
totaldays=$(( $($date -d "$endmon/$endday/$endyear" +%j) - $($date +%j) ))
else
#### Calculate this in chunks, starting with days left in this year.
#### DAYS LEFT IN START YEAR
# Calculate the date string format for the specified starting date.
thisdatefmt="$thismon/$thisday/$thisyear"
calculate="$($date -d "12/31/$thisyear" +%j) - $($date -d $thisdatefmt +%j)"
daysleftinyear=$(( $calculate ))
#### DAYS IN INTERVENING YEARS
daysbetweenyears=0
tempyear=$(( $thisyear + 1 ))
while [ $tempyear -lt $endyear ] ; do
daysbetweenyears=$(( $daysbetweenyears + \
$($date -d "12/31/$tempyear" +%j) ))
tempyear=$(( $tempyear + 1 ))
done
#### DAYS IN END YEAR
dayofyear=$($date --date $endmon/$endday/$endyear +%j) # That's easy!
#### NOW ADD IT ALL UP
totaldays=$(( $daysleftinyear + $daysbetweenyears + $dayofyear ))
fi
echo "There are $totaldays days until the date $endmon/$endday/$endyear."
exit 0
该脚本与 daysago 脚本的逻辑相似,但计算方向相反。它会先进行一系列输入验证,确保输入的日期是未来日期。然后根据输入日期和当前日期的关系,分情况计算距离指定日期的天数。
运行示例:
$ daysuntil 1 1 2020
There are 1321 days until the date 1/1/2020.
$ daysuntil 12 25 2025
There are 3506 days until the date 12/25/2025.
$ daysuntil 7 4 2076
There are 21960 days until the date 7/4/2076.
$ daysuntil 1 1 3000
There are 359259 days until the date 1/1/3000.
5. 在Windows 10上安装Bash
在Windows 10上安装Bash需要满足以下条件:
- 运行Windows 10周年更新版(版本号14393)。
- 拥有x64兼容处理器。
- 加入Windows Insider计划。
安装步骤如下:
1. 加入Windows Insider计划 :访问 https://insider.windows.com/ 并加入该计划。使用Windows 10升级助手将系统更新到周年更新版,更新完成后重启电脑。
2. 启用开发者模式 :
- 打开“设置”,搜索“开发者模式”。
- 在“使用开发者功能”部分选择“开发者模式”。
- 点击通过警告提示后,Windows会下载并安装一些额外的软件,这可能需要几分钟时间。
3. 启用Windows Subsystem for Linux (Beta) :
- 搜索“启用或关闭Windows功能”。
- 在弹出的窗口中,勾选“适用于Linux的Windows子系统(Beta)”。
- 点击“确定”,然后重启电脑以完全启用Linux子系统和新的开发者工具。
4. 安装Bash :
- 在开始菜单中搜索“命令提示符”并打开。
- 在命令提示符中输入 bash ,然后按照提示输入 y 开始下载Bash软件。
- 下载、编译和安装过程可能需要一些时间,完成后,系统会提示你输入Unix用户名和密码,你可以随意选择,无需与Windows用户名和密码匹配。
安装完成后,在命令提示符中输入 bash 即可使用。不过,目前Windows上的Bash更像是一个新奇的功能,对于Windows 10用户来说,其实际用途可能有限。如果你想更深入地学习Linux,建议通过双启动或在虚拟机中运行完整的Linux发行版。
6. 批量重命名文件脚本
bulkrename 脚本用于批量重命名文件,代码如下:
#!/bin/bash
# bulkrename--Renames specified files by replacing text in the filename
printHelp()
{
echo "Usage: $0 -f find -r replace FILES_TO_RENAME*"
echo -e "\t-f The text to find in the filename"
echo -e "\t-r The replacement text for the new filename"
exit 1
}
while getopts "f:r:" opt
do
case "$opt" in
r ) replace="$OPTARG" ;;
f ) match="$OPTARG" ;;
? ) printHelp ;;
esac
done
shift $(( $OPTIND - 1 ))
if [ -z $replace ] || [ -z $match ]
then
echo "You need to supply a string to find and a string to replace";
printHelp
fi
for i in $@
do
newname=$(echo $i | sed "s/$match/$replace/")
mv $i $newname
&& echo "Renamed file $i to $newname"
done
该脚本接收三个参数:要查找的文本、要替换的文本和要重命名的文件列表。它会遍历文件列表,使用 sed 命令将文件名中的匹配文本替换为指定的文本,然后使用 mv 命令进行重命名。
使用示例:
$ bulkrename -f old_text -r new_text file1.txt file2.txt file3.txt
这个脚本可以帮助系统管理员在处理大量文件时,快速、方便地完成文件重命名任务。
综上所述,这些脚本在日期计算和文件处理方面提供了强大的功能,而在Windows 10上安装Bash则为Windows用户提供了一种体验Linux环境的途径。无论是系统管理员还是普通用户,都可以根据自己的需求选择合适的工具和脚本。
日期处理脚本与Windows 10上Bash安装指南
7. 脚本功能总结与对比
为了更清晰地了解上述脚本的功能和特点,下面通过表格进行总结对比:
| 脚本名称 | 功能 | 输入参数 | 依赖工具 | 注意事项 |
| — | — | — | — | — |
| dayinpast | 查找过去特定日期是星期几 | 月份、日期、年份 | GNU date或ncal | 若不支持GNU date,使用ncal获取日历信息 |
| daysago | 计算过去某个日期距离今天的天数 | 月份、日期、年份 | GNU date | 需验证日期有效性,考虑闰年情况 |
| daysuntil | 计算距离未来某个日期还有多少天 | 月份、日期、年份 | GNU date | 输入日期需为未来日期,进行多种参数检查 |
| bulkrename | 批量重命名文件 | 要查找的文本、要替换的文本、文件列表 | sed、mv | 需提供查找和替换的字符串 |
通过这个表格,我们可以直观地看出每个脚本的主要功能、所需的输入参数以及依赖的工具,方便在不同场景下选择合适的脚本。
8. 脚本优化与拓展思路
虽然上述脚本已经能够完成基本的任务,但在实际使用中,我们还可以对它们进行优化和拓展,以满足更多的需求。以下是一些具体的思路:
- dayinpast脚本 :
- 支持更多日期格式 :目前脚本只支持“月 日 年”的输入格式,可以增加对“月/日/年”等常见格式的支持。
- 输出国际化 :可以根据不同的语言环境,将星期几的输出进行本地化处理。
- daysago和daysuntil脚本 :
- 处理边界情况 :当前脚本对一些边界情况的处理还不够完善,例如输入的日期是未来几天或过去几天的情况,可以增加相应的判断和处理逻辑。
- 增加更多输出信息 :除了输出天数,还可以输出具体的日期范围、包含的闰年数量等信息。
- bulkrename脚本 :
- 支持正则表达式 :在查找和替换文本时,支持使用正则表达式,提高脚本的灵活性。
- 增加备份功能 :在重命名文件之前,先对文件进行备份,以防误操作。
9. 实际应用场景分析
这些脚本在实际生活和工作中有着广泛的应用场景,下面结合具体案例进行分析。
场景一:历史事件日期查询
在研究历史事件时,我们可能需要了解某个事件发生的具体星期几。例如,想要知道美国独立宣言签署的1776年7月4日是星期几,就可以使用 dayinpast 脚本:
$ dayinpast 7 4 1776
That was a Thursday.
通过这个脚本,我们可以快速获取历史事件发生的星期信息,为历史研究提供便利。
场景二:个人时间管理
在个人生活中,我们可能会关心自己已经活了多少天,或者距离某个重要日期还有多少天。比如,想知道从自己出生到现在过了多少天,或者距离下一次生日还有多少天,可以分别使用 daysago 和 daysuntil 脚本。
# 计算从出生到现在的天数
$ daysago 5 10 1990
12000 days have elapsed between 5/10/1990 and today, day 200 of 2024.
# 计算距离下一次生日的天数
$ daysuntil 5 10 2025
200 days until the date 5/10/2025.
这样,我们可以更好地规划自己的生活,珍惜时间。
场景三:系统文件管理
系统管理员在管理大量文件时,经常需要对文件进行批量重命名。例如,将一批文件名中包含“old_text”的部分替换为“new_text”,可以使用 bulkrename 脚本:
$ bulkrename -f old_text -r new_text file1.txt file2.txt file3.txt
Renamed file file1.txt to file1_new_text.txt
Renamed file file2.txt to file2_new_text.txt
Renamed file file3.txt to file3_new_text.txt
通过这个脚本,系统管理员可以快速、准确地完成文件重命名任务,提高工作效率。
10. 总结与展望
本文介绍了几个实用的日期处理和文件重命名脚本,包括 dayinpast 、 daysago 、 daysuntil 和 bulkrename ,并详细说明了在Windows 10上安装Bash的步骤。这些脚本和工具为我们在日期计算、文件处理和系统操作方面提供了便利,无论是个人用户还是系统管理员都可以从中受益。
未来,随着技术的不断发展,我们可以进一步优化和拓展这些脚本的功能,使其更加智能化和人性化。例如,结合人工智能技术,实现对日期和文件的智能分析和处理;或者开发更加友好的用户界面,让用户更容易使用这些脚本。同时,我们也可以将这些脚本集成到其他系统中,形成更加完善的解决方案,满足更多复杂的应用场景需求。
总之,这些脚本和工具为我们的生活和工作带来了很多便利,我们应该充分利用它们,并不断探索和创新,让它们发挥更大的作用。
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B{选择脚本类型}:::decision
B -->|dayinpast| C(输入月、日、年):::process
B -->|daysago| D(输入月、日、年):::process
B -->|daysuntil| E(输入月、日、年):::process
B -->|bulkrename| F(输入查找文本、替换文本、文件列表):::process
C --> G(判断是否支持GNU date):::decision
G -->|是| H(使用date -d输出星期几):::process
G -->|否| I(使用ncal获取日历信息):::process
I --> J(提取星期缩写并转换):::process
D --> K(输入验证和闰年判断):::process
K --> L(计算起始年剩余天数):::process
L --> M(计算中间年总天数):::process
M --> N(获取当前年已过天数):::process
N --> O(汇总天数):::process
E --> P(输入验证确保为未来日期):::process
P --> Q{是否同年}:::decision
Q -->|是| R(计算天数差):::process
Q -->|否| S(计算今年剩余天数):::process
S --> T(计算中间年总天数):::process
T --> U(计算目标年已过天数):::process
U --> V(汇总天数):::process
F --> W(遍历文件列表):::process
W --> X(使用sed替换文件名):::process
X --> Y(使用mv重命名文件):::process
H --> Z([结束]):::startend
J --> Z
O --> Z
R --> Z
V --> Z
Y --> Z
这个流程图展示了各个脚本的主要执行流程,从选择脚本类型开始,到最终输出结果结束,清晰地呈现了每个脚本的处理逻辑。
超级会员免费看
2

被折叠的 条评论
为什么被折叠?



