Ste*_*fan 32 directory mv macos
我有一个foo
包含多个文件的目录:
.
??? foo
??? a.txt
??? b.txt
Run Code Online (Sandbox Code Playgroud)
我想将它移动到一个同名的目录中:
.
??? foo
??? foo
??? a.txt
??? b.txt
Run Code Online (Sandbox Code Playgroud)
我目前正在创建一个临时目录bar
,然后foo
进入bar
并重命名bar
为foo
:
mkdir bar
mv foo bar
mv bar foo
Run Code Online (Sandbox Code Playgroud)
但这感觉有点麻烦,我必须为bar
尚未使用的名称选择一个名称。
有没有更优雅或更直接的方法来实现这一目标?如果这很重要,我在 macOS 上。
Kus*_*nda 22
要在当前目录中安全地创建一个临时目录,其名称尚未被采用,您可以mktemp -d
像这样使用:
tmpdir=$(mktemp -d "$PWD"/tmp.XXXXXXXX) # using ./tmp.XXXXXXXX would work too
Run Code Online (Sandbox Code Playgroud)
该mktemp -d
命令将在给定路径上创建一个目录,路径X
名末尾的-es 将替换为随机字母数字字符。它将返回创建的目录的路径名,我们将此值存储在tmpdir
. 1
tmpdir
然后可以在执行您已经在执行的相同过程时使用此变量,并bar
替换为"$tmpdir"
:
mv foo "$tmpdir"
mv "$tmpdir" foo
unset tmpdir
Run Code Online (Sandbox Code Playgroud)
将unset tmpdir
在年底只是删除了变量。
1 通常,人们应该能够将TMPDIR
环境变量设置为想要使用 来创建临时文件或目录的目录路径mktemp
,但是 macOS 上的实用程序在这方面的工作方式似乎与其他 BSD 系统上的相同实用程序略有不同,并将在完全不同的位置创建目录。然而,上述内容适用于 macOS。如果默认临时目录在另一个分区上并且该目录包含大量数据(即它会很慢),则使用稍微方便一些tmpdir=$(TMPDIR=$PWD mktemp -d)
甚至tmpdir=$(TMPDIR=. mktemp -d)
只会在 macOS上出现问题foo
。
mur*_*uru 10
在 macOS 上,您可以rename
使用 Homebrew安装命令(Perl 脚本):
brew install rename
Run Code Online (Sandbox Code Playgroud)
然后使用-p
(a la mkdir
) 让它创建任何必要的目录,并-A
添加一个前缀:
% mkdir -p foo/bar; touch foo/{a,b}.txt foo/bar/c.txt
% rename -p -A foo/ foo/*
% tree foo
foo
??? foo
??? a.txt
??? b.txt
??? bar
??? c.txt
Run Code Online (Sandbox Code Playgroud)
运行-n
以显示更改而不重命名(试运行):
% rename -p -A foo/ foo/* -n
'foo/a.txt' would be renamed to 'foo/foo/a.txt'
'foo/b.txt' would be renamed to 'foo/foo/b.txt'
'foo/bar' would be renamed to 'foo/foo/bar'
Run Code Online (Sandbox Code Playgroud)
如果您有 dot 文件,以便简单的*
不会拿起它们,然后使用其他方法rename
:
使用bash,(MIS)的使用GLOBIGNORE
来获得*
匹配点文件:
$ GLOBIGNORE=.; rename -p -A foo/ foo/* -n
'foo/.baz' would be renamed to 'foo/foo/.baz'
'foo/a.txt' would be renamed to 'foo/foo/a.txt'
'foo/b.txt' would be renamed to 'foo/foo/b.txt'
'foo/bar' would be renamed to 'foo/foo/bar'
Run Code Online (Sandbox Code Playgroud)或使用find
with-print0
和rename
with -0
:
% find foo -mindepth 1 -maxdepth 1 -print0 | rename -0 -p -A foo/ -n
Reading filenames from STDIN
Splitting on NUL bytes
'foo/b.txt' would be renamed to 'foo/foo/b.txt'
'foo/a.txt' would be renamed to 'foo/foo/a.txt'
'foo/bar' would be renamed to 'foo/foo/bar'
'foo/.baz' would be renamed to 'foo/foo/.baz'
Run Code Online (Sandbox Code Playgroud)bxm*_*bxm 10
只要内容不足以超过最大参数限制(并且您不介意“可接受”的错误消息),那么它不需要比这更复杂:
mkdir foo/foo
mv foo/* foo/foo
Run Code Online (Sandbox Code Playgroud)
处理隐藏文件的修正:
mkdir foo/foo
mv foo/{.,}* foo/foo
Run Code Online (Sandbox Code Playgroud)
我建议反过来。不要移动目录,而只移动它的内容:
.
??? foo
??? a.txt
??? b.txt
Run Code Online (Sandbox Code Playgroud)
mkdir foo/foo
Run Code Online (Sandbox Code Playgroud)
.
??? foo
??? foo
??? a.txt
??? b.txt
Run Code Online (Sandbox Code Playgroud)
cd foo
mv $(ls | grep -v '^foo$') foo
cd -
Run Code Online (Sandbox Code Playgroud)
.
??? foo
??? foo
??? a.txt
??? b.txt
Run Code Online (Sandbox Code Playgroud)
如果你有 bash,你也可以这样做
shopt -s extglob
cd foo
mv !(foo) foo
cd -
Run Code Online (Sandbox Code Playgroud)
(如所描述的在这里),以避免运行LS和grep。
这个解决方案的优点是它非常简单。
缺点(如评论中所指出的):
ls -A
修复它,但不是ls -a
)mv "$(ls | grep -v '^foo$')" foo
大多数缺点可以通过使用一些 bash 技巧来解决,但如果必须处理疯狂的文件名,最好使用更强大的方法,如其他答案中所述。
你已经基本搞定了。您可以为瞬态目录选择不同的名称,例如具有当前日期/时间(以纳秒为单位)和我们的 PID 作为复合后缀的目标名称,但这仍然假定目录尚不存在:
dir=foo # The directory we want to nest
now=$(date +'%s_%N') # Seconds and nanoseconds
mkdir "$dir.$now.$$" # Create a transient directory
mv -f "$dir" "$dir.$now.$$/" # Move our directory inside transient directory
mv -f "$dir.$now.$$" "$dir" # Rename the transient directory to the name with which we started
Run Code Online (Sandbox Code Playgroud)
如果你想要一个有保证的强大解决方案,我会循环mkdir
直到它成功
now=$(date +'%s_%N')
while ! mkdir -m700 "$dir.$now.$$" 2>/dev/null
do
sleep 0.$$
now=$(date +'%s_%N')
done
Run Code Online (Sandbox Code Playgroud)
小智 6
mkdir foo/foo && mv foo/!(foo) foo/foo
Run Code Online (Sandbox Code Playgroud)
您需要 cd 进入源文件夹 (foo) 所在的目录。
然后运行上面的命令。它将创建一个同名文件夹,并将父 foo 的内容移动到子 foo 目录(子目录除外,因此使用 ! 指定)。
如果子 foo 目录已经存在,您可以忽略第一部分并运行 mv 命令:
mv foo/!(foo) foo/foo
Run Code Online (Sandbox Code Playgroud)
在 MacOS 中,您可能需要设置 extglob 选项:
shopt -s extglob
Run Code Online (Sandbox Code Playgroud)