我有一个foo
包含几个文件的目录:
.
└── foo
├── a.txt
└── b.txt
我想将它移动到同名的目录中:
.
└── foo
└── foo
├── a.txt
└── b.txt
我目前正在创建一个临时目录bar
,然后移入foo
并重bar
命名bar
为foo
:
mkdir bar
mv foo bar
mv bar foo
但这感觉有点麻烦,我必须为bar
尚未使用的名称选择一个名称。
有没有更优雅或更直接的方法来实现这一目标?如果这很重要,我在 macOS 上。
要在当前目录中安全地创建一个临时目录,使用尚未使用的名称,您可以
mktemp -d
像这样使用:该
mktemp -d
命令将在给定路径上创建一个目录,X
路径名末尾的 -es 将替换为随机字母数字字符。它将返回创建的目录的路径名,我们将这个值存储在tmpdir
. 1tmpdir
然后可以在遵循您已经在执行的相同过程时使用此变量,并bar
替换为"$tmpdir"
:最后
unset tmpdir
的只是删除变量。1 通常,人们应该能够将
TMPDIR
环境变量设置为一个目录路径,在该目录路径中可以使用mktemp
.并将在完全不同的位置创建目录。但是,上述内容适用于 macOS。如果默认临时目录位于另一个分区并且该目录包含大量数据(即它会很慢),则使用稍微更方便tmpdir=$(TMPDIR=$PWD mktemp -d)
甚至tmpdir=$(TMPDIR=. mktemp -d)
只会在 macOS 上成为问题。foo
在 macOS 上,您可以
rename
使用 Homebrew 安装命令(Perl 脚本):然后使用
-p
(a lamkdir
) 让它创建任何必要-A
的目录,并添加前缀:运行
-n
以显示更改而不重命名(试运行):如果您有点文件,那么简单的文件
*
就不会拾取它们,那么请使用其他方法rename
:使用 bash,(mis)use
GLOBIGNORE
来*
匹配点文件:或使用
find
with-print0
和rename
with-0
:只要内容不足以超过最大参数限制,(并且您不介意“可接受的”错误消息),那么它不需要比这更复杂:
处理隐藏文件的修正:
我建议反过来。不要移动目录,只移动它的内容:
如果你有 bash,你也可以这样做
(如此处所述)以避免运行 ls 和 grep。
这个解决方案的优点是它非常简单。
缺点(正如评论中指出的那样):
ls -A
修复它,但不是ls -a
)mv "$(ls | grep -v '^foo$')" foo
大多数缺点可以通过使用一些 bash 技巧来解决,但如果必须处理疯狂的文件名,最好使用更健壮的方法,如其他答案中所述。
你已经很确定了。您可以为瞬态目录选择一个不同的名称,例如以纳秒为单位的当前日期/时间和我们的 PID 作为复合后缀的目标名称,但这仍然假定该目录尚不存在:
如果您想要一个有保证的强大解决方案,我会循环
mkdir
直到它成功您需要 cd 进入源文件夹 (foo) 所在的目录。
然后运行上面的命令。它将创建一个同名文件夹并将父 foo 的内容移动到子 foo 目录(子目录除外,因此使用 ! 名称)。
如果子 foo 目录已经存在,您可以忽略第一部分并运行 mv 命令:
在 MacOS 中,您可能需要设置 extglob 选项:
除了上述建议之外,您可能还想签出 rsync。在我开始之前,请务必记住在不使用
--dry-run
rsync 之前使用该选项。--dry-run
它将告诉你现实生活中会发生什么。rsync 有许多选项,不仅可以帮助复制/移动文件,还可以加快进程。这是完成工作的一种方法。该
--remove-source-files
选项在移动过程之后从源中删除文件(实际上是一个副本,然后是一个删除)。请注意,rsync 命令首先读取 foo 的内容,在名为 foo 的现有目录中创建目录 foo,然后启动复制过程。它以删除 foo 中的源文件结束。注意:特别注意目录名称的斜杠。许多人在上面指出了其他考虑因素(如符号链接),但 a
man rsync
将帮助您选择所需的选项。此处请注意:由于您已要求提供文件解决方案,因此这将起作用。这不会删除将留下的空目录。我不知道没有额外步骤的方法,所以如果有人可以添加这个,在此先感谢!a = 存档模式
v = 详细
只需不要触摸 foo ,您就不会遇到名称相同的问题。相反,在其中创建一个具有相同名称的目录并将所有内容移到那里。使用 $_ 技巧和 && 使它成为一个单行:
这将引发一个您可以忽略的无害错误(mv: rename foo to foo/foo: Invalid argument)。
优于其他答案的优势:您只需要键入一次目录名称,因此您不会因拼写错误而出错。
您可以将其与其他答案混合使用以获得更好的效果:
mv {.,}* $_
将处理隐藏文件(以您也可以忽略的更多错误为代价)mv ./!(foo)
将避免错误消息,但前提是您设置shopt -s extglob
这实际上看似简单,我很震惊没有其他人提供这个答案,所以我在这里使用以下示例......
现在是神奇的部分
现在为什么这行得通?因为我只是一个新手,所以我不能给你最准确的答案——但我明白这归结为
/
文件夹中尾随字符的处理方式。仔细看那个 mv 命令
$ mv ./bar/foo ./foo/
请注意,文件的目标文件夹是如何指定不带尾随的
/
,而共享目标文件夹名称的目标是使用尾随/
' 指定的。这是你的神奇门票,如果你不注意,它会咬你的屁股。很抱歉,我目前无法提供比这更详尽的答案,但也许知识更流利的人会冒昧地编辑我的答案。
无论如何,这似乎是最简单直接的解决方案,只需使用一次
ls
命令,无需创建中间文件夹。希望对你有用,加油!