【问题标题】:Bash simple script copying files to specific folder + renaming to todays effective dateBash简单脚本将文件复制到特定文件夹+重命名为今天的生效日期
【发布时间】:2020-06-29 14:28:47
【问题描述】:

美好的一天, 我需要您的帮助来创建下一个脚本
每天老师上传下一种格式的文件:

STUDENT_ACCOUNTS_20200217074343-20200217.xlsx  
STUDENT_MARKS_20200217074343-20200217.xlsx  
STUNDENT_HOMEWORKS_20200217074343-20200217.xlsx  
STUDENT_PHYSICAL_20200217074343-20200217.xlsx  
SUBSCRIBED_STUDENTS_20200217074343-20200217.xlsx

[file_name+todaydatetime-todaydate.xlsx]

但有时老师没有上传这些文件,我们需要手动重命名前一天收到的文件,然后将每个单独的文件复制到单独的文件夹,例如:

cp STUDENT_ACCOUNTS_20200217074343-20200217.xlsx /incoming/A1/STUDENT_ACCOUNTS_20200318074343-20200318.xlsx  
cp STUDENT_MARKS_20200217074343-20200217.xlsx  /incoming/B1/STUDENT_ACCOUNTS_20200318074343-20200318.xlsx  
.............

cp SUBSCRIBED_STUDENTS_20200217074343-20200217.xlsx /incoming/F1/SUBSCRIBED_STUDENTS_20200318074343-20200318.xlsx.  

简而言之 - 将前一个日期的文件复制到具有新时间戳的特定文件夹。

#!/bin/bash
cd /home/incoming/
date=$(date '+%Y%m%d')
previousdate="$( date --date=yesterday '+%Y%m%d' )"
cp /home/incoming/SUBSCRIBED_STUDENTS_'$previousdate'.xlsx /incoming/F1/SUBSCRIBED_STUDENTS_'$date'.xlsx  

有时老师可以上传一个文件而其他文件不能,如何检查现有文件? 感谢您阅读本文,如果您能帮助我,我将不胜感激 - 您将为我节省大量体力劳动。

【问题讨论】:

  • 为什么previousdate 只是今天带有连字符?我想也许你想要previousdate="$( date --date=yesterday '+%Y%m%d' )"
  • 谢谢你是对的
  • 试试for i in /home/incoming/SUBSCRIBED_STUDENTS_*; do echo $i; done
  • 您可以使用for循环来重复任务。

标签: bash shell automation


【解决方案1】:

如果您的目录结构已知,该过程可以完全自动化。如果它遵循某种模式,请在此处提及。

对于时间安排,这可能会有所帮助:

文件名“tscp”

#
# Stands for timestamped cp
#
tscp() {

    local file1=$1 ; shift
    local to_dir=$1 ; shift
    local force_copy=$1 ; shift

    local current_date="$(date '+%Y%m%d')"

    if [ "${force_copy}" == "--force" ] ; then
        cp "${file1}" "${to_dir}/$(basename ${file1%-*})-${current_date}.xlsx"
    else
        cp -n "${file1}" "${to_dir}/$( basename ${file1%-*})-${current_date}.xlsx"
    fi
}

tscp "$@"

用法如下:

tscp source to_directory [-—force]

脚本基本上有 2 个参数,第三个是可选的。

第一个 arg 是源文件路径,第二个是要复制到的目录路径(. 如果相同的目录)。

默认情况下,当且仅当目标文件不存在时才会生成此副本。

如果你想覆盖目标文件然后传递第三个参数—force

同样,这可以根据所提供的细节进一步细化。

现在的示例用法:

bash tscp SUBSCRIBED_STUDENTS_20200217074343-20200217.xlsx /incoming/F1/

将 SUBSCRIBED_STUDENTS_20200217074343-20200217.xlsx 复制到目录 /incoming/F1/ 如果它尚不存在更新日期。

更新:

试一试:

#! /usr/bin/env bash

printf_err() {
    ERR_COLOR='\033[0;31m'
    NORMAL_COLOR='\033[0m'
    printf "${ERR_COLOR}$1${NORMAL_COLOR}" ; shift
    printf "${ERR_COLOR}%s${NORMAL_COLOR}\n" "$@" >&2
}

alias printf_err='printf_err "Line ${LINENO}: " '
shopt -s expand_aliases

usage() {

    printf_err \
        "" \
        "usage: ${BASH_SOURCE##*/} " \
        "  -f copy_data_file" \
        "  -d days_before" \
        "  -m months_before" \
        "  -o" \
        "  -y years_before" \
        "  -r " \
        "  -t to_dir" \
            >&2

    exit 1
}

fullpath() {
    local path="$1" ; shift
    local abs_path

    if [ -z "${path}" ] ; then
        printf_err "${BASH_SOURCE}: Line ${LINENO}: param1(path) is empty"
        return 1
    fi

    abs_path="$( cd "$( dirname "${path}" )" ; pwd )/$( basename ${path} )"

    printf "${abs_path}"
}

OVERWRITE=0
REVIEW=0
COPYSCRIPT="$( mktemp "/tmp/copyscriptXXXXX" )"

while getopts 'f:d:m:y:t:or' option
do
    case "${option}" in
        d)
            DAYS="${OPTARG}"
            ;;
        f)
            INPUT_FILE="${OPTARG}"
            ;;
        m)
            MONTHS="${OPTARG}"
            ;;
        t)
            TO_DIR="${OPTARG}"
            ;;
        y)
            YEARS="${OPTARG}"
            ;;
        o)
            OVERWRITE=1
            ;;
        r)
            REVIEW=1
            COPYSCRIPT="copyscript"
            ;;
        *)
            usage
            ;;
    esac
done

INPUT_FILE=${INPUT_FILE:-$1}
TO_DIR=${TO_DIR:-$2}

if [ ! -f "${INPUT_FILE}" ] ; then
    printf_err "No such file ${INPUT_FILE}"
    usage
fi


DAYS="${DAYS:-1}"
MONTHS="${MONTHS:-0}"
YEARS="${YEARS:-0}"

if date -v -1d > /dev/null 2>&1; then
    # BSD date

    previous_date="$( date -v -${DAYS}d -v -${MONTHS}m -v -${YEARS}y '+%Y%m%d' )"

else
    # GNU date

    previous_date="$( date --date="-${DAYS} days -${MONTHS} months -${YEARS} years" '+%Y%m%d' )"

fi

current_date="$( date '+%Y%m%d' )"

tmpfile="$( mktemp "/tmp/dstnamesXXXXX" )"


awk -v to_replace="${previous_date}" -v replaced="${current_date}" '{

    gsub(to_replace, replaced, $0)
    print

}' ${INPUT_FILE} > "${tmpfile}"


paste ${INPUT_FILE} "${tmpfile}" |
    while IFS=$'\t' read -r -a arr
    do
        src=${arr[0]}
        dst=${arr[1]}
        opt=${arr[2]}

        if [ -n "${opt}" ] ; then

            if [ ! -d "${dst}" ] ;
            then
                printf_err "No such directory ${dst}"
                usage
            fi

            dst="${dst}/$( basename "${opt}" )"

        else

            if [ ! -d "${TO_DIR}" ] ; 
            then
                printf_err "No such directory ${TO_DIR}"
                usage
            fi

            dst="${TO_DIR}/$( basename "${dst}" )"
        fi

        src=$( fullpath "${src}" )
        dst=$( fullpath "${dst}" )

        if [ -n "${OVERWRITE}" ] ; then
            echo "cp ${src} ${dst}"
        else
            echo "cp -n ${src} ${dst}"
        fi
    done > "${COPYSCRIPT}"


if [ "${REVIEW}" -eq 0 ] ; then

    ${BASH} "${COPYSCRIPT}"
    rm "${COPYSCRIPT}"

fi

rm "${tmpfile}"

步骤:

  1. 将上述脚本存储在一个文件中,例如 `tscp`。
  2. 现在您需要为其创建输入文件。 从您的示例中,示例输入文件可能如下所示:
    STUDENT_ACCOUNTS_20200217074343-20200217.xlsx         /incoming/A1/
    STUDENT_MARKS_20200217074343-20200217.xlsx         /incoming/B1/
    STUNDENT_HOMEWORKS_20200217074343-20200217.xlsx  
    STUDENT_PHYSICAL_20200217074343-20200217.xlsx  
    SUBSCRIBED_STUDENTS_20200217074343-20200217.xlsx         /incoming/FI/
    

    第一部分是源文件名,在“选项卡”之后(肯定是选项卡),您提到目标目录。这些路径应该是您执行脚本的目录的绝对路径或相对路径。

    如果所有路径都将发送到同一目录(稍后讨论),则您可能不会提及目标目录。
    假设您将此文件命名为“文件”。

    此外,您实际上不必输入所有内容。如果当前目录中有这些文件,只需执行以下操作:
    ls -1 > file
    
    (上面是 ls "one",而不是 "l"。)
  3. 现在我们有了上面的`file`,我们没有提到所有的目标目录,而只是提到了一些。 假设我们要将所有其他目录移动到 `/incoming/x` 并且它存在。

    现在脚本将像这样执行:
    bash tscp -f file -t /incoming/x -r
    
    其中 `/incoming/x` 是默认目录,即当 `file` 中没有提及其他目录时,您的文件将移动到该目录。

    现在在当前目录中将生成一个名为 `copyscript` 的脚本,其中将包含用于复制所有文件的 `cp` 命令。您可以打开评论“copyscript”,如果复制看起来正确,请继续:
    bash copyscript
    
    这将复制所有文件,然后您可以:
    rm copyscript
    
  4. 您不需要生成到 `copyscript` 并且可以立即获取如下副本:
    bash tscp -f file -t /incoming/x
    
    它不会生成任何文案并立即复制。

    以前 `-r` 导致了 `copyscript` 的生成。 我会建议使用带有 `-r` 的版本,因为这样更安全一些,并且您会确保正在制作正确的副本。
  5. 默认情况下,它会检查前一天并重命名为当前日期,但您可以将该行为覆盖为:
    bash tscp -f file -t /incoming/x -d 3
    
    `-d 3` 将在 `file` 中查找 3 天前的文件。
  6. 默认情况下,副本不会覆盖,即如果目标文件已经存在,则不会制作副本。 如果要覆盖,请添加标志 `-o`。

作为结论,我建议使用:

bash tscp -f file -r

file 包含上面所有的制表符分隔值。

此外,在您确定它可以正常工作后,将 tscp 添加到路径中将是一个好主意。

此外,scipt 是在mac 上制作的,并且始终存在所用工具的版本冲突变化。我建议先在一些示例数据上尝试脚本,以确保脚本在您的机器上正常工作。

【讨论】:

  • 感谢您的帮助,我可以输入脚本已经预定义的文件名,我知道这些文件名将在传入文件夹中吗?像 :``` file1=STUDENT_MARKS_[previousdatetime].xlsx file2= STUDENT_ACCOUNTS_[Previousdatetime].xlsx -> 复制 file1 到 /incoming/F1-[todaydate]/STUDENT_MARKS_[todaydate].xlsx 和 file2 到 /incoming/A1-[ todaydate]/STUDENT_ACCOUNTS[todaydate].xlsx .``` 抱歉提出愚蠢的问题,有 15 个文件应该使用这样的工作流程,当然还有检查,例如 file1=/incoming/F1-[todaydate]/STUDENT_MARKS_[ todaydate] 已经存在。如果你有贝宝,请分享:)
  • @Kwaker,您可以将名称硬编码到脚本中,但我不会真正建议您这样做。相反,您可以拥有一个包含所有文件名的文本文件,脚本可以通过该文本文件循环并执行任务。可以为此目的设计一个简单的实用程序。就像您使用 cp 命令一样。您可以拥有自己的版本cp,并带有自定义选项,让您的生活更轻松。就像您可以拥有cp —date-rename <src_file> <dst_file>cp —file <textfile>(用于重命名以时间戳方式提及的所有文件)。那会有好处吗? ...在下一条评论中继续.....
  • contd...如果这听起来不错,我将更新答案以反映更改并提供说明以使其易于使用。如果您对该实用程序有更多要求,您可以更新问题。至于paypal的事情,我真的很感激,但在这里回答只是我的爱好,不过我会更新答案,直到你的问题得到解决。
  • 是的,不同的文件将进入不同的文件夹,所以我也想对其进行硬编码。我认为对您来说更简单的方法是更好的解决方案,再次感谢
  • @Kwaker,我晚上回家后更新答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 2018-12-27
  • 2015-11-19
相关资源
最近更新 更多