Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 移动与包含的文件同名的文件_Linux_Shell - Fatal编程技术网

Linux 移动与包含的文件同名的文件

Linux 移动与包含的文件同名的文件,linux,shell,Linux,Shell,很聪明的人会觉得讽刺吗?在他们自己的目录中提取了6000多个归档文件,但有时归档文件包含一个文件:与它包含的目录同名 例如: mydir(0001)/mydir(0001).txt mydir(ZREZ)/mydir(ZREZ).txt mydir(AAEZ)/mydir(AAREZ).txt mydir(AAEZ)/otherfile.txt mydir(QQQQ)/mydir(QQQQ).txt ... 如果只有一个文件和它所在的目录,Unix shell是否有一种快速方法来比较该文件,如

很聪明的人会觉得讽刺吗?在他们自己的目录中提取了6000多个归档文件,但有时归档文件包含一个文件:与它包含的目录同名

例如:

mydir(0001)/mydir(0001).txt
mydir(ZREZ)/mydir(ZREZ).txt
mydir(AAEZ)/mydir(AAREZ).txt
mydir(AAEZ)/otherfile.txt
mydir(QQQQ)/mydir(QQQQ).txt
...
如果只有一个文件和它所在的目录,Unix shell是否有一种快速方法来比较该文件,如果没有扩展名,则将其移到上面一个目录并删除现在为空的目录

所以我应该得到:

mydir(0001).txt
mydir(ZREZ).txt
mydir(AAEZ)/mydir(AAREZ).txt
mydir(AAEZ)/otherfile.txt
mydir(QQQQ).txt
...

您可以从所有6000个目录/文件的父目录中使用如下脚本:

while IFS= read -d '' -r d; do
    n=$(find "$d" -maxdepth 1 -type f -exec echo . \; | wc -l)
    f="${d}/${d}.txt"
    [[ $n -eq 1 && -f "$f" ]] && mv "$f" "$d/../" && rmdir "$d"
done < <(find . -type d ! -name '.' -print0)

您可以使用父目录中的一行程序执行此操作:

for i in */*; do [ -f "${i%/*}/${i%/*}.txt" ] && mv "$i" . && rm -d "${i%/*}"; done
由于人们对在没有rm-d的BSD上同样起作用的解决方案感兴趣,因此可以通过以下方式实现:

for i in */*; do [ -f "${i%/*}/${i%/*}.txt" ] && mv "$i" . && [ -z "$(ls -A "${i%/*}")" ] && rm -r "${i%/*}"; done
在mv之后,检查剩余目录是否为空,如果为空,则删除该目录,否则保持该目录不变

输出:


如果需要,还可以在移动文件后-删除目录之前,测试目录是否为空。如图所示

这应该可以解决问题。这比anubhava的脚本要简单一些,但仍然要注意只移动文件和删除目录(如果这是唯一的内容)

for x in *; do
  if [[ $(find "$x" | sed 1d | head -n2) == "$x/$x.txt" ]]; then
    mv "$x/$x.txt" . && rmdir "$x"
  fi
done

您可以将其剪切粘贴到父目录中的命令行。它在该目录中为x in*循环所有文件,如果其中任何文件本身是仅包含单个文件$x/$x.txt的目录,则它将移动该文件并删除该目录。

这是我的脚本,基于Anubhava的第一个答案。对初学者的风格感到抱歉:

#!/bin/bash
# loop & print a folder recusively,
folder_recurse() {
    for i in "$1"/*;do
        if [ -d "$i" ];then
            n=$(find "$i" -maxdepth 1 -exec echo . \; | wc -l)
            d=$(readlink -f "${i}")
            g=$d"/"$(basename "$i")".epub"
            if [[ $n -eq 2 && -f "$g" ]]; then
                echo "Doing: $i"
                mv "$g" "$d/.."
                rmdir "$d"
            fi
            folder_recurse "$i"
    done
}


# try get path from param
path=""
if [ -d "$1" ]; then
    path=$1;
else
    path="/tmp"
fi

echo "base path: $path"
folder_recurse $path

看看dirname和basenamecommands@JimGarrison非常感谢。在这样评论之前,你要花2飞秒才能看到我的个人资料。你会发现我不是你的答案所暗示的那个懒惰的人。如果我问是因为我没有在网上找到任何有价值的东西,我想可能已经有人这么做了。希望不是所有人都认为DIY,懒惰的家伙只是写下你可能认为的礼貌的版本。在给出的例子中,这将删除dir mydirAAEZ,即使它包含otherfile.txt。不,没有名为mydirAAEZ的文件-但重点是,我在答案的末尾掉了一个便条。不,你错了。代码的功能完全符合要求。你的假想在便笺中有记载。你总是可以发明一些不受保护、不被要求的案例。如果这是你的事-好吧。我匆忙中误读了示例数据。然后,基于我的误读,我匆忙删除了我的评论。如此匆忙浪费!不管怎样,您的scriptlet基于示例数据做出了一个糟糕且可能具有破坏性的假设,OP表示该示例数据代表了一个更大的数据库。没有理由这样假设。OP在Linux上,没有rm-d,因为这是一个BSDism。如果遇到:mydir0001/mydir0002.txt会发生什么?非常感谢,但是如何递归使用它?=将我的所有文件发送到脚本?David,在这种情况下,它不会移动文件,因为根据OP的描述,它不应该移动。Olivier,假设我理解正确,您将所有档案解压到单个父目录下的各自目录中,那么您只需在父目录内的命令行上剪切粘贴即可。即使它有多行,它也会在bash中正确地剪切粘贴,我假设它是您的shell。如果这有助于揭开它的神秘面纱,我会添加更多的描述。试过你说的:它是即时的,没有任何作用。我试过了,它不起作用。你确定是-exec echo吗。而不是-exec echo{}?您可以单独运行find命令。这是一种计算给定子目录的所有文件和目录的方法。尝试运行find./subdir-maxdepth 1-exec echo.\ |wc-l来看看你得到了什么。好的,谢谢你,但它不是递归的,它只是在第一级停止。可能是因为我不知道如何注入/精确所有目录?不清楚所有这些目录/文件是在同一级别还是在嵌套的子目录中,这就是为什么我只为一个级别写这篇文章。它也可以修改为深入。让我来编辑。你不应该真的那样做。这和我的答案差不多。这对那些花时间想出答案的海报是不公平的。您可以将此作为问题的编辑发布,但删除接受标记不是SO社区的其他成员所做的。好的,我检查了您的答案是否有效:/
#!/bin/bash
# loop & print a folder recusively,
folder_recurse() {
    for i in "$1"/*;do
        if [ -d "$i" ];then
            n=$(find "$i" -maxdepth 1 -exec echo . \; | wc -l)
            d=$(readlink -f "${i}")
            g=$d"/"$(basename "$i")".epub"
            if [[ $n -eq 2 && -f "$g" ]]; then
                echo "Doing: $i"
                mv "$g" "$d/.."
                rmdir "$d"
            fi
            folder_recurse "$i"
    done
}


# try get path from param
path=""
if [ -d "$1" ]; then
    path=$1;
else
    path="/tmp"
fi

echo "base path: $path"
folder_recurse $path