31、日期处理脚本与Windows 10上Bash安装指南

日期处理脚本与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

这个流程图展示了各个脚本的主要执行流程,从选择脚本类型开始,到最终输出结果结束,清晰地呈现了每个脚本的处理逻辑。

基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究(Matlab代码实现)内容概要:本文围绕“基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究”,介绍了利用Matlab代码实现配电网可靠性的仿真分析方法。重点采用序贯蒙特卡洛模拟法对配电网进行长时间段的状态抽样统计,通过模拟系统元件的故障修复过程,评估配电网的关键可靠性指标,如系统停电频率、停电持续时间、负荷点可靠性等。该方法能够有效处理复杂网络结构设备时序特性,提升评估精度,适用于含分布式电源、电动汽车等新型负荷接入的现代配电网。文中提供了完整的Matlab实现代码案例分析,便于复现和扩展应用。; 适合人群:具备电力系统基础知识和Matlab编程能力的高校研究生、科研人员及电力行业技术人员,尤其适合从事配电网规划、运行可靠性分析相关工作的人员; 使用场景及目标:①掌握序贯蒙特卡洛模拟法在电力系统可靠性评估中的基本原理实现流程;②学习如何通过Matlab构建配电网仿真模型并进行状态转移模拟;③应用于含新能源接入的复杂配电网可靠性定量评估优化设计; 阅读建议:建议结合文中提供的Matlab代码逐段调试运行,理解状态抽样、故障判断、修复逻辑及指标统计的具体实现方式,同时可扩展至不同网络结构或加入更多不确定性因素进行深化研究。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值