如果不存在,有没有办法让mv创建要移动到的目录?


275

因此,如果我位于主目录中,并且想将foo.c移至〜/ bar / baz / foo.c,但是这些目录不存在,则可以通过某种方式自动创建这些目录,以便您只需要输入

mv foo.c ~/bar/baz/ 

一切都会解决?看来您可以将mv别名为一个简单的bash脚本,该脚本将检查那些目录是否存在,如果不存在,将调用mkdir然后是mv,但是我想我会检查是否有人有更好的主意。


Answers:


294

这个单线(bash)怎么样:

mkdir --parents ./some/path/; mv yourfile.txt $_

分解:

mkdir --parents ./some/path

创建目录(包括所有中间目录),然后:

mv yourfile.txt $_

将文件移动到该目录($ _扩展到传递给上一个shell命令的最后一个参数,即:新创建的目录)。

我不确定这在其他shell中还能用多远,但是可能会为您提供一些有关查找内容的想法。

这是使用此技术的示例:

$ > ls
$ > touch yourfile.txt
$ > ls
yourfile.txt
$ > mkdir --parents ./some/path/; mv yourfile.txt $_
$ > ls -F
some/
$ > ls some/path/
yourfile.txt

32
不错,带有“ $ _”。
dmckee ---前主持人小猫,

1
为什么./到处都有多余的痴迷?args不是没有.目录的PATH命令...
Jens

3
对于新手,
parents

8
奇怪的是,--parents在macOS 10.13.2上不可用。您需要使用-p
Joshua Pinter

1
如果移动文件,例如./some/path/foo,则不起作用。在这种情况下,命令应为:mkdir -p ./some/path/foo; mv yourfile.txt $_:h
hhbilly

63
mkdir -p `dirname /destination/moved_file_name.txt`  
mv /full/path/the/file.txt  /destination/moved_file_name.txt

2
我是唯一意识到此代码没有意义的人?您以递归方式创建现有文件的绝对路径(这意味着该路径已存在),然后将文件移动到某个位置(在您的示例中不存在)。
vdegenne

1
@ user544262772 GNU coreutils' dirname不需要其参数存在,它是纯字符串操作。不能代表其他发行版。此代码无错。
TroyHurts

我认为,这是最容易实现自动化的答案。for f in *.txt; do mkdir -p `dirname /destination/${f//regex/repl}`; mv "$f" "/destination/${f//regex/repl}; done
凯尔(Kyle)

23

另存为名为mv或mv.sh的脚本

#!/bin/bash
# mv.sh
dir="$2"
tmp="$2"; tmp="${tmp: -1}"
[ "$tmp" != "/" ] && dir="$(dirname "$2")"
[ -a "$dir" ] ||
mkdir -p "$dir" &&
mv "$@"

或者将〜/ .bashrc文件的末尾作为函数替换每个新终端上的默认mv。使用函数可以使bash保留其内存,而不必每次都读取脚本文件。

function mv ()
{
    dir="$2"
    tmp="$2"; tmp="${tmp: -1}"
    [ "$tmp" != "/" ] && dir="$(dirname "$2")"
    [ -a "$dir" ] ||
    mkdir -p "$dir" &&
    mv "$@"
}

这些基于Chris Lutz的提交。


3
这最准确地回答了恕我直言的问题。用户想要增强的mv命令。对于脚本编写尤其有用,即,您不一定要运行检查并在mkdir -p需要使用时随时运行mv。但是由于我希望使用默认的错误行为mv,因此我将函数名称更改为mvp-以便知道何时可以创建目录。
Brian Duncan 2014年

似乎是最好的解决方案,但是实现会崩溃很多。
Ulises Layera 2015年

2
@UlisesLayera我修改了算法,使其更加健壮。它现在不应该崩溃
Sepero,2015年

有人可以解释一下[ ! -a "$dir" ]我进行的实验的含义,其中右半部分为真和假,都被评估为真。出于其他原因,tmp =“ $ {tmp:-1}”似乎抓住了文件的最后一个字符以确保它不是路径(/)
bazz 2015年

@bazz应该做的是“如果$ dir不存在,则继续”。不幸的是,您是对的,使用“!-a”时存在错误,我不知道为什么。我已经对代码进行了一些编辑,现在应该可以了。
Sepero

13

您可以使用mkdir

mkdir -p ~/bar/baz/ && \
mv foo.c ~/bar/baz/

自动执行此操作的简单脚本(未经测试):

#!/bin/sh

# Grab the last argument (argument number $#)    
eval LAST_ARG=\$$#

# Strip the filename (if it exists) from the destination, getting the directory
DIR_NAME=`echo $2 | sed -e 's_/[^/]*$__'`

# Move to the directory, making the directory if necessary
mkdir -p "$DIR_NAME" || exit
mv "$@"

当我运行“ $ dirname〜?bar / baz /”时,我得到的是“ / home / dmckee / bar”,这不是您想要的...
dmckee ---前主持人小猫

@dmckee,嗯,你是对的。关于如何解决这个问题的任何想法?如果输入〜/ bar / baz,则(a)要复制到〜/ bar /并重命名为baz,或者(b)复制到〜/ bar / baz /。有什么更好的工作工具?
斯特拉格

@dmckee,我使用了regexp / sed来提出解决方案。它按您的喜好起作用吗?=]
斯特拉格

很好,除非$ 2不是最后一个参数,除非$#=2。我有一个程序la输出其最后一个参数。我曾经在cp命令的版本中使用它(如果最后一个参数不是目录,则添加当前目录)。即使是现代外壳,也仅支持$ 1 .. $ 9;Perl脚本可能更好。
乔纳森·莱夫勒

@Leffler,不是真的-我知道bash支持9个以上的参数(使用$ {123}是一种方法)。我不认识Perl,所以随时可以自己回答。=]
斯特拉格

7

听起来答案是否定的:)。我并不是真的想创建一个别名或func只是为了做到这一点,通常是因为它是一次性的,而且我已经在键入mv命令了,但是我发现有一个很好的解决方案:

mv *.sh  shell_files/also_with_subdir/ || mkdir -p $_

如果mv失败(dir不存在),它将创建目录(这是上一个命令的最后一个参数,也是如此$_)。因此,只需运行此命令,然后up重新运行它,这一次mv应该会成功。


5

以下shell脚本,也许?

#!/bin/sh
if [[ -e $1 ]]
then
  if [[ ! -d $2 ]]
  then
    mkdir --parents $2
  fi
fi
mv $1 $2

那是基本部分。您可能需要添加一些内容来检查参数,并且如果目标存在,源目录存在或不存在(即,不要覆盖不存在的内容),则可能需要更改行为。 。


1
使用您的代码,如果目录不存在,则不会执行移动!
斯特拉格

1
而且您错过了mkdir的“ -p”标志。
dmckee ---前主持人小猫,

如果目录不存在,为什么只想移动它就创建它?(固定-p标志)
克里斯·卢茨

我的意思是,当您运行脚本并且目录$ 2不存在时,会创建目录,但不会复制文件。
斯特拉格

他给出了一个简单的结构,并增加了有关如何扩展它的信息。为什么投票呢?
ypnos

5

仅当目标路径中的最后一个目录不存在时,rsync命令才能发挥作用,例如,对于~/bar/baz/if 的目标路径bar存在但baz不存在,则可以使用以下命令:

rsync -av --remove-source-files foo.c ~/bar/baz/

-a, --archive               archive mode; equals -rlptgoD (no -H,-A,-X)
-v, --verbose               increase verbosity
--remove-source-files   sender removes synchronized files (non-dir)

在这种情况下,baz将创建目录(如果不存在)。但是,如果双方barbaz没有存在的rsync将失败:

sending incremental file list
rsync: mkdir "/root/bar/baz" failed: No such file or directory (2)
rsync error: error in file IO (code 11) at main.c(657) [Receiver=3.1.2]

因此,基本上,rsync -av --remove-source-files用作的别名应该是安全的mv


4

最简单的方法是:

mkdir [directory name] && mv [filename] $_

假设我下载了位于下载目录(~/download)中的pdf文件,并且想将所有文件都移到一个不存在的目录中(假设my_PDF)。

我将输入以下命令(确保当前工作目录为~/download):

mkdir my_PDF && mv *.pdf $_

如果要创建子目录,可以像这样添加-p选项mkdir:(假设我要创建一个名为的子目录python):

mkdir -p my_PDF/python && mv *.pdf $_

2

更安静,但工作方式:

mkdir -p $2
rmdir $2
mv $1 $2

使用mkdir -p创建包含共享目标文件名的临时目录的目录,然后使用简单的rmdir删除该文件名目录,然后将文件移至新目标。我认为使用dirname的答案可能是最好的。


是的,有点傻。:-)如果$ 2是一个目录(如原始问题所示),那么它将失败,因为最后一个目录将被删除,因此'mv'将失败。并且如果$ 2已经存在,那么它也会尝试将其删除。
Tylla

谢谢!这正是我需要完成的任务:mv ./old ./subdir/new尚未存在subdir的地方
Mike Murray

2
((cd src-path && tar --remove-files -cf - files-to-move) | ( cd dst-path && tar -xf -))

1

码:

if [[ -e $1 && ! -e $2 ]]; then
   mkdir --parents --verbose -- "$(dirname -- "$2")"
fi
mv --verbose -- "$1" "$2"

例:

参数:“ d1”“ d2 / sub”

mkdir: created directory 'd2'
renamed 'd1' -> 'd2/sub'

1

这将移至带有父目录foo.c的新baz目录bar

mv foo.c `mkdir -p ~/bar/baz/ && echo $_`

将根据需要创建中间目录的-p选项mkdir
在没有-p所有目录的情况下,路径前缀必须已经存在。

反引号内的所有内容都``将执行,并且输出将作为命令的一部分内联返回。
由于mkdir不返回任何内容,因此只会将输出结果echo $_添加到命令中。

$_将最后一个参数引用到先前执行的命令。
在这种情况下,它将返回~/bar/baz/传递给mkdir命令的新目录()的路径。


我解压缩了一个归档文件,但未提供目标位置,并想将除demo-app.zip当前目录以外的所有文件移至名为的新目录demo-app
以下代码可以解决问题:

mv `ls -A | grep -v demo-app.zip` `mkdir -p demo-app && echo $_`

ls -A返回所有文件名,包括隐藏文件(隐式.和除外..)。

管道符号|用于将ls命令的输出管道传输到grep命令行,纯文本搜索实用程序)。
-v标志指示grep查找并返回除以外的所有文件名demo-app.zip
该文件列表作为move命令的源参数添加到我们的命令行中mv。目标参数是新目录的路径,该目录传递到mkdir使用引用$_并使用输出echo


1
这是一个很好的细节和解释级别,尤其是在第一篇文章中。谢谢!
杰里米·卡尼

谢谢@JeremyCaney!我很高兴开始提供帮助!
伊万·旺德

0

您甚至可以使用大括号扩展名:

mkdir -p directory{1..3}/subdirectory{1..3}/subsubdirectory{1..2}      
  • 创建3个目录(directory1,directory2,directory3),
    • 在每个子目录中都有两个子目录(子目录1,子目录2),
      • 在每个子目录中都有两个子目录(子目录1和子目录2)。

您必须使用bash 3.0或更高版本。


5
有趣,但没有回答OP的问题。
Alexey Feldgendler,2012年

0
$what=/path/to/file;
$dest=/dest/path;

mkdir -p "$(dirname "$dest")";
mv "$what" "$dest"

1
要使其成为独立的sh脚本,只需将$ dest和$ src替换为$ 1和$ 2
cab404 '16

0

我的一串解决方案:

test -d "/home/newdir/" || mkdir -p "/home/newdir/" && mv /home/test.txt /home/newdir/

0

您可以链接命令:mkdir ~/bar/baz | mv foo.c ~/bar/baz/
或shell脚本在这里:

#!/bin/bash
mkdir $2 | mv $1 $2

1.打开任何文本编辑器
。2.复制粘贴 shell脚本。
3.将另存mkdir_mv.sh。4.
输入脚本的目录:cd your/script/directory
5.更改文件模式chmod +x mkdir_mv.sh
6.设置别名alias mv="./mkdir_mv.sh"
现在,无论何时运行,mv如果不存在命令创建目录,都会创建命令移动目录。


0

根据另一个答案中的注释,这是我的shell函数。

# mvp = move + create parents
function mvp () {
    source="$1"
    target="$2"
    target_dir="$(dirname "$target")"
    mkdir --parents $target_dir; mv $source $target
}

将其包含在.bashrc或类似文件中,以便您可以在任何地方使用它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.