可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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