我有一个包含几个子目录的目录,其中包含文件。
我想按名称字母顺序对每个目录中的文件进行排序,并将每个目录中的第一个文件复制到给定的新目录。
- 我想忽略隐藏文件。
- 如果目标目录中有同名文件,则两个文件都应保留。
样本:
parentdir
->dir1
->afile
->bfile
->cfile
->dir2
->dfile
->efile
->ffile
->dir3
->afile
->hfile
->ifile
我想运行一个命令来填充我的新目录,如下所示:
newdir
->afile
->afile.1
->dfile
如何才能做到这一点?
答案1
我想最简单的方法是使用ls
来列出文件,默认情况下它按字母顺序排列(并省略隐藏文件),使用 获取每个目录中的第一个文件head
,然后使用一些 shell 代码来找出文件名它们应该被复制到。正如这个 bash 脚本中所示:
for d in ./*/; do
src="$(ls "$d" | head -n 1)"
dstbase="newdir/$(basename "$src")"
if [[ ! -f "$dstbase" ]]; then
cp "$src" "$dstbase"
else
suffix=1
while [[ -f "$dstbase.$suffix" ]]; do
let suffix++
done
cp "$src" "$dstbase.$suffix"
fi
done
显然,您必须根据实际情况调整文件路径。这也相当脆弱,因为如果您希望在复制时排除 、 等目录dir1
下的任何目录,则可能会出现问题。dir2
它还在循环中存在潜在的竞争条件,用于查找未使用的文件名;这可能不会成为问题,但不要做任何事情,比如并行运行多个副本。
答案2
这可以通过以下一行来实现:
ls -ltr /parent_directory_path/ |
awk '$1~"^drw" {print $9}' |
while read line; do
ls -l $line |
awk '$1 ~ "^-r" {print $9}' |
head -1 |
awk -v line="$line" '{print "cp -rvfp" " " line"/"$1 " " "/newdir/" }';
done |
sh
答案3
与zsh
GNU cp
:
cd parentdir &&
for dir (*(/)) (cp --backup=numbered -- $dir/*(.[1]) newdir/)
实现--backup=numbered
了一个备份方案,其中文件被命名为file.~1~
, file.~2~
... 因此,第一个副本将是file.~max~
最后一个副本(如果您想要颠倒顺序,则file
向后处理列表(*(/On)
而不是))。*(/)
POSIXly,你可以这样做:
cp_numbered() (
suffix=
n=0
while [ -e "$2$suffix" ] || [ -L "$2$suffix" ]; do
suffix=.$((n += 1))
done
exec cp -- "$1" "$2$suffix"
)
cd parentdir &&
for dir in */; do
for file in "$dir"/*; do
if [ -f "$file" ]; then
cp_numbered "$file" "newdir/${file#*/}"
continue 2
fi
done
done