简体   繁体   中英

List the files in Directory and Copy-Replace them into another Directory in Linux

I am trying to automate the below: Any help, please.
We have 2 directories as mentioned below, whenever we get new files in Directory-1, only they should be copied and replaced into Directory-2. How to achieve this in Linux scripting. Filename remains the same but the version will be different.

Directory-1:
FileOne_2.0.0.txt
FileTwo_3.0.0.txt

Directory-2:
FileOne_1.0.0.txt
FileTwo_2.0.0.txt
FileThree_3.0.0.txt
FileFive_5.0.0.txt

Try this code ( on a test setup before you trust your real directories and files with it ):

#! /bin/bash -p

shopt -s extglob    # Enable extended globbing ( +([0-9]) ... )
shopt -s nullglob   # Globs that match nothing expand to nothing
shopt -s dotglob    # Globs match files with names starting with '.'

srcdir='Directory-1'
destdir='Directory-2'

# A(n extended) glob pattern to match a version string (e.g. '543.21.0')
readonly kVERGLOB='+([0-9]).+([0-9]).+([0-9])'

# shellcheck disable=SC2231 # (Bad warning re. unquoted ${kVERGLOB})
for srcpath in "$srcdir"/*_${kVERGLOB}.txt; do
    srcfile=${srcpath##*/}  # E.g. 'FileOne_2.0.0.txt'
    srcbase=${srcfile%_*}   # E.g. 'FileOne'

    # Set and check the path that the file will be moved to
    destpath=$destdir/$srcfile
    if [[ -e $destpath ]]; then
        printf "Warning: '%s' already exists.  Skipping '%s'.\\n" \
                "$destpath" "$srcpath" >&2
        continue
    fi

    # Make a list of the old versions of the file
    # shellcheck disable=SC2206 # (Bad warning re. unquoted ${kVERGLOB})
    old_destpaths=( "$destdir/$srcbase"_${kVERGLOB}.txt )
    # TODO: Add checks that the number of old files (${#old_destpaths[*]})
    #       is what is expected (exactly one?)

    # Move the file
    if mv -i -- "$srcpath" "$destpath"; then
        printf "Moved '%s' to '%s'\\n" "$srcpath" "$destpath" >&2
    else
        printf "Warning: Failed to move '%s' to '%s'.  Skipping '%s'.\\n" \
                "$srcpath" "$destpath" "$srcpath" >&2
        continue
    fi

    # Remove the old version(s) of the file (if any)
    for oldpath in "${old_destpaths[@]}"; do
        if rm -- "$oldpath"; then
            printf "Removed  '%s'\\n" "$oldpath" >&2
        else
            printf "Warning: Failed to remove '%s'.\\n" "$oldpath" >&2
        fi
    done
done
  • The code is Shellcheck -clean. Two Shellcheck suppression comments are used because the unquoted expansions are necessary here.
  • srcdir and destdir are set to constant values. You might want to take them from command line parameters, or set them to different constant values.
  • The code could be made shorter by removing checks. However, moves and removes are destructive operations that can do a lot of damage if they are done incorrectly. I'd add even more checks if it was my own data.
  • See glob - Greg's Wiki for an explanation of the "extended globbing" used in the code.
  • See Parameter expansion [Bash Hackers Wiki] for an explanation of ${srcpath##*/} and ${srcfile%_*} .
  • mv -i is used as a double protection against overwriting an existing file.
  • All external commands are invoked with -- to explicitly end options, in case they are ever used with paths that begin with - .
  • Make sure that you understand the code and test it VERY carefully before using it for real.
source_dir=./files/0
dest_dir=./files/1/
for file in $source_dir/*
do
  echo $file
  echo "processing"
  if [[ "1" == "1" ]]; then
    mv $file $dest_dir
  fi
done

Where processing and the 1 == 1 is whatever your 'prechecks' are (which you haven't told us)

If your coreutils sort is newer than or equal to v7.0 (2008-10-5) after which sort command supports -V option (version-sort), would you please try:

declare -A base2ver base2file

# compare versions
# returns 0 if $1 equals to $2
#         1 if $1 is newer than $2
#        -1 if $1 is older than $2
vercomp() {
    if [[ $1 = $2 ]]; then
        echo 0
    else
        newer=$(echo -e "$1\n$2" | sort -Vr | head -n 1)
        if [[ $newer = $1 ]]; then
            echo 1
        else
            echo -1
        fi
    fi
}

for f in Directory-1/*.txt; do
    basename=${f##*/}
    version=${basename##*_}
    version=${version%.txt}       # version number such as "2.0.0"
    basename=${basename%_*}       # basename such as "FileOne"
    base2ver[$basename]=$version  # associates basename with version number
    base2file[$basename]=$f       # associates basename with full filename
done

for f in Directory-2/*.txt; do
    basename=${f##*/}
    version=${basename##*_}
    version=${version%.txt}
    basename=${basename%_*}

    if [[ -n ${base2ver[$basename]} ]] && (( $(vercomp "${base2ver[$basename]}" "$version") > 0 )); then
#       echo "${base2file[$basename]} is newer than $f"
        rm -- "$f"
        cp -p -- "${base2file[$basename]}" Directory-2
    fi
done

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM