我有一些包含大量文件的目录。由于其中一些文件正在接近600k文件,因此它们已成为一个难以处理的主要问题。只列出文件正在慢慢成为处理它们的应用程序的主要瓶颈。
文件的名称如下: id_date1_date2.gz 我决定将文件拆分成几个较小的文件,具体取决于第一部分“id”。
由于相同的id可能会显示在大量文件中,并且相同的ID已经显示在几个目录中,我需要跟踪已复制的文件ID以及dirs。 否则我最终会复制疯狂的次数,或者从dir Y复制时丢失id X,如果已经从dir Z复制的话。
我写了一个脚本来完成这个。一些调试包括
#!/bin/bash
find /marketdata -maxdepth 2 -type d | grep "[0-9]\.[0-9][0-9][0-9]$" | sort | #head -n2 | tail -n1 |
while read baseDir; do
cd $baseDir;
echo $baseDir > tmpFile;
find . -type f | grep -v "\.\/\." | #sort | head -n4 |
while read file; do
name=$(awk 'BEGIN {print substr("'"$file"'", 3,index("'"$file"'", "_")-3 )}');
dirkey=${baseDir//[\/,.]/_}"_"$name;
if [ "${copied[$dirkey]}" != "true" ]; then
echo "Copying $baseDir/$name with:";
echo mkdir -p $(sed 's/data/data4/' tmpFile)/$name;
#mkdir -p $(sed 's/data/data4/' tmpFile)/$name;
oldName=$baseDir/$name"_*";
echo cp $oldName "$(sed 's/data/data4/' tmpFile)/$name/";
#cp $oldName "$(sed 's/data/data4/' tmpFile)/$name/";
echo "Setting $dirkey to true";
copied[$dirkey]="true";
else
echo "$dirkey: ${copied[$dirkey]}"
sleep 1
fi
done;
rm tmpFile;
done
这里的问题是复制中的所有键的值似乎从第一次复制时变为真,因此我对bash数组的处理可能就是问题所在。
取得一些进展: 我尝试将每个密钥写入文件,并在每次迭代时,将该文件读入数组。这显然是非常丑陋,但看起来它实现了我的目标。可能因为我处理了几千个id而变得非常慢。稍后会更新。
对于将来可能会发现这一点的其他人,这是最终的脚本:
declare -A copied
find /marketdata -maxdepth 2 -type d -name "[0-9]\.[0-9][0-9][0-9]" | sort | #head -n3 | tail -n1 |
while read baseDir; do
cd $baseDir;
find . -type f | grep -v "\.\/\." | sort | #head -n100 |
while read file; do
length=$(expr index "$file" "_");
name=${file:2:$((length - 3))};
dirkey=${baseDir//[\/,.]/_}"_"$name;
if [ "${copied[$dirkey]}" != "true" ]; then
echo "Copying ${baseDir}/${name} to ${baseDir//data/data4}/$name";
mkdir -p "${baseDir//data/data4}/$name";
oldName="${baseDir}/${name}_*";
cp -n $oldName "${baseDir//data/data4}/${name}/";
copied[$dirkey]="true";
fi
done;
done
没有awk,没有sed,更好的引用,没有写入临时文件到光盘,更少grep。 我不确定dirkey hack是否有必要,因为关联数组正常工作,我也不完全理解为什么我需要oldName var。
答案 0 :(得分:1)
如果$dirkey
中的值包含字母字符,则必须使用在Bash 4之前不可用的关联数组。如果您使用的是Bash 4且键是字母数字而不是简单的数字,在脚本顶部添加以下内容:
declare -A copied
补充意见:
您在某些地方使用参数展开,而在其他地方使用sed
。您可以在(可能)所有情况下使用大括号扩展。
我建议不要像$var"literal"$var
那样引用,而是像"${var}literal${var}"
那样做,或者如果文字不会被模糊地解释为变量名称的一部分,你可以省略大括号:{{ 1}}。
使用"literal$var"
代替复杂awk
引用的变量:"'"
。
在循环中调用外部可执行文件会使事情变得非常缓慢,特别是如果它一次只处理一个值(或数据行)。 'sed awk -v awkvar=$shellvar '{print awkvar}'
awk`命令可以转换为参数扩展形式。
GNU commands that I mentioned are examples of this. Also, your
有一个正则表达式功能,您可以使用而不是find
。
应引用包含文件名的所有变量名称。
答案 1 :(得分:0)
cp的-n选项在这种情况下非常有用。如果文件已经在目的地,您可以放心。
-n, --no-clobber
do not overwrite an existing file (overrides
a previous -i option)
这基本上就是说你在谈论你做同样的工作两次离开的情况。您可以将关注点拆分为移动所有文件,仅移动之前未移动过的文件。