How to move files from X sub_dir to Y sub_dir

2019-05-16 03:21发布

问题:

I have main DIR X and inside this I have many sub directories like A,B,C,D. I have main DIR Y and inside this i have many sub directories with same name as X main directory sub directories like A,B,C,D.

Now I need to MOVE only files from X main dir sub directories to Y main directory sub directory.

Eg:

Inside main directory X ,sub directory A has 100 files

and B has 1 file

and C has 5 files

and D has 50 files...

my cursor should be at main DIR X , from there I need to MOVE all the sub directory files to same named sub directories(A,B,C,D) which is there inside Y main directory.

how can I do this in SHELL SCRIPTING(KSH) or unix??

回答1:

Note: Fundamentally revised to come up with a simpler solution. One-liners (more complex) at the bottom.

A POSIX-compliant solution:

#!/bin/sh

# Specify source and target directories (example values)
dirFrom='/tmp/from'
dirTo='/tmp/to'

# Use globbing to find all subdirectories - note the trailing '/'
# to ensure that only directories match.
for subdir in "$dirFrom"/*/; do

  # Extract the mere name.
  # Note that using ${subdir##*/} is NOT an option here, because $subdir ends in '/'.
  name=$(basename -- "$subdir")

  # Make sure a subdirectory of the same
  # name exists in the target dir.
  mkdir -p "$dirTo/$name"

  # Move all items in the source subdir. to the analogous target subdir.
  mv "$subdir"* "$dirTo/$name/"

done  

The above will therefore work with ksh as well, and also other POSIX-compatible shells such as bash and zsh.

There are two potential problems with this solution:

  • Hidden items (those whose name starts with a .) are ignored.
  • The script will break, if there are no subdirs. or if any of them is empty, because a globbing pattern such as * that does not match anything is left as-is, resulting in non-existent paths being passed to mv.

More robust Bash version

Bash - unlike ksh, unfortunately - has options that address both issues:

  • shopt -s dotglob causes hidden items to be included when globbing is performed.
  • shopt -s nullglob causes patterns that don't match anything to expand to the empty string.
#!/usr/bin/env bash

# Specify source and target directories (example values)
dirFrom='/tmp/from'
dirTo='/tmp/to'

shopt -s dotglob   # include hidden items when matching `*`
shopt -s nullglob  # expand patterns that don't match anything to the emtpy string

# Use globbing to find all subdirectories - note the trailing '/'
# to ensure that only directories match.
for subdir in "$dirFrom"/*/; do

  # Extract the mere name.
  # Note that using ${subdir##*/} is NOT an option here, because $subdir ends in '/'.
  name=$(basename -- "$subdir")

  # Make sure a subdirectory of the same
  # name exists in the target dir.
  mkdir -p "$dirTo/$name"

  # Collect the paths of the items in the subdir. in 
  # an array, so we can test up front whether anything matched.
  itms=( "$subdir"* )

  # Move all items in the source subdir. to the analogous target subdir,
  # but only if the subdir. contains at least 1 item.
  [[ ${#itms[@]} -gt 0 ]] && mv "${itms[@]}" "$dirTo/$name/"

done
  • Note how shopt -s nullglob by itself was not enough - we still had to collect globbing matches in an array first, so we could determine if anything matched.
    • While we could instead just use 2>/dev/null to let mv fail silently if there are no matches, this is not advisable, because it could mask true error conditions.

If you're interested in one-liners, here are find-based commands; they are, however, quite complex.

# Note: Both solutions below ignore symlinks to directories as subdirectories.

# [POSIX-compliant] Excluding hidden items.
# Note how `\! -name '.*'` is explicitly added to the `find` command to ensure that no hidden subdirs. are matched, so as to
# to match the shell globbing behavior of excluding hidden items.
find "$dirFrom" -mindepth 1 -maxdepth 1 -type d \! -name '.*' -exec sh -c \
  'f=$1 t=$2/${1##*/}; set -- "$f"/*; [ -e "$1" ] && mkdir -p "$t" && mv "$@" "$t"' \
  - {} "$dirTo" \;

# [Bash] Including hidden items.
find "$dirFrom" -mindepth 1 -maxdepth 1 -type d -exec bash -O dotglob -c \
  'f=$1 t=$2/${1##*/}; set -- "$f"/*; [[ -e $1 ]] && mkdir -p "$t" && mv "$@" "$t"' \
  - {} "$dirTo" \;


回答2:

Here is a shell script which should work. I have not had time to check it though. Please check and confirm.

#!/bin/bash

##################################################################
#
#   Please make sure this script is run from source     
#   directory. Also you need to have read, write and    
#   execute permission for this directory.
#
#   If the subdirectories with same names are not present   
#   then those will be created directly.
##################################################################

# Replace name of source directory by "X"
sourcedir="X"

# Replace name of destination directory with complete path by "Y"
destdir="/home/user/Y"

# Copying names of all subdirectories in a temporary text file
ls -Rl | grep "[a-z]:" | sed 's/://' | cut -c 2- > temp.txt

# Moving files directory by directory to destination
while read line; do
    mv $sourcedir$line/* $destdir$line/
    echo "All files from directory $sourcedir$line moved to $destdir$line"
done < temp.txt

rm temp.txt


回答3:

You can use script as below:

#!/bin/bash
dirX=X
dirY=Y
for subdir in `ls $dirX`; do
        mv $dirX$subdir/* $dirY$subdir
done

Replace X, Y with your directory