有没有一种方法让mv创建目录要移动到如果它不存在?

所以,如果我在我的主目录下,我想把foo.c移动到~/bar/baz/foo.c,但是这些目录不存在,有没有什么方法可以自动创建这些目录,这样你只需要输入

mv foo.c ~/bar/baz/

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

295545 次浏览

你可以使用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 "$@"

也许是下面的shell脚本?

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

这是最基本的部分。你可能想要添加一些来检查参数,如果目标目录存在,或者源目录存在,或者不存在(即不要覆盖不存在的东西),你可能想要改变行为。

下面的一行代码怎么样(在bash中):

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

分解一下:

mkdir --parents ./some/path
# if it doesn't work; try
mkdir -p ./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

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

mkdir -p directory{1..3}/subdirectory{1..3}/subsubdirectory{1..2}
  • 创建3个目录(directory1, directory2, directory3),
    • 并且每个子目录中都有两个子目录(subdirectory1, subdirectory2),
      • 每个目录中都有两个子目录(subsubdirectory1和subsubdirectory2)。
      • 李< / ul > < / > 李< / ul > < / >

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

保存为名为mv.sh的脚本

#!/bin/bash
# mv.sh
dir="$2" # Include a / at the end to indicate directory (not filename)
tmp="$2"; tmp="${tmp: -1}"
[ "$tmp" != "/" ] && dir="$(dirname "$2")"
[ -a "$dir" ] ||
mkdir -p "$dir" &&
mv "$@"

或者在~/后面加上。Bashrc文件作为一个函数,在每个新终端上替换默认mv。使用函数可以让bash保持内存,而不必每次都读取脚本文件。

function mvp ()
{
dir="$2" # Include a / at the end to indicate directory (not filename)
tmp="$2"; tmp="${tmp: -1}"
[ "$tmp" != "/" ] && dir="$(dirname "$2")"
[ -a "$dir" ] ||
mkdir -p "$dir" &&
mv "$@"
}

使用示例:

mv.sh file ~/Download/some/new/path/ # <-End with slash

这些都是根据克里斯·卢茨提交的。

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

更傻,但有效的方式:

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

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

听起来答案是否定的:)。我并不想仅仅为了这样做而创建一个别名或func,通常是因为它是一次性的,而且我已经在输入mv命令的过程中,但我发现了一些很好的方法:

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

如果mv失败(dir不存在),它将使目录(这是上一个命令的最后一个参数,所以$_有它)。所以只要运行这个命令,然后向上重新运行它,这一次mv应该会成功。

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


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

最简单的方法是:

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

让我们假设我下载了位于我的下载目录(~/download)中的pdf文件,我想将它们全部移动到一个不存在的目录(比如说my_PDF)。

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

mkdir my_PDF && mv *.pdf $_

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

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

我的解决方案是:

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

代码:

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'

rsync命令可以在目标路径不存在的情况下完成此操作,例如,对于~/bar/baz/的目标路径,如果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的别名应该是安全的。

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

这将把foo.c移动到新目录baz和父目录bar

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

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

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

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


我解压缩了一个归档文件,但没有给出目的地,并想将除demo-app.zip之外的所有文件从当前目录移动到名为demo-app的新目录。

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

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

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

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

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

将它包含在.bashrc或类似文件中,这样你就可以在任何地方使用它。

利用将最后一个参数传递给shell脚本;中的技巧,我们可以创建一个简单的shell函数,无论你想移动多少个文件,它都能正常工作:

# Bash only
mvdir() { mkdir -p "${@: -1}" && mv "$@"; }


# Other shells may need to search for the last argument
mvdir() { for last; do true; done; mkdir -p "$last" && mv "$@"; }

使用如下命令:

mvdir foo.c foo.h ~/some/new/folder/

在将文件批量移动到新的子目录时,我经常遇到这个问题。理想情况下,我想这样做:

mv * newdir/

这个线程中的大多数答案都建议mkdir,然后mv,但这导致:

mkdir newdir && mv * newdir
mv: cannot move 'newdir/' to a subdirectory of itself

我面临的问题略有不同,因为我想全面移动所有内容,并且,如果我在移动之前创建了新目录,那么它也会尝试将新目录移动到自己。所以,我通过使用父目录来解决这个问题:

mkdir ../newdir && mv * ../newdir && mv ../newdir .

警告:不能在根文件夹(/)中工作。

我在linux上用install命令完成了这一点:

root@logstash:# myfile=bash_history.log.2021-02-04.gz ; install -v -p -D $myfile /tmp/a/b/$myfile


bash_history.log.2021-02-04.gz -> /tmp/a/b/bash_history.log.2021-02-04.gz

唯一的缺点是文件权限被改变了:

root@logstash:# ls -lh /tmp/a/b/


-rwxr-xr-x 1 root root 914 Fev  4 09:11 bash_history.log.2021-02-04.gz

如果你不介意重置权限,你可以使用:

-g, --group=GROUP   set group ownership, instead of process' current group
-m, --mode=MODE     set permission mode (as in chmod), instead of rwxr-xr-x
-o, --owner=OWNER   set ownership (super-user only)

对于这个问题,有很多相互矛盾的解决方案,以下是对我们有效的解决方案:

## ss_mv ##
function ss_mv {
mkdir -p $(dirname "$2") && mv -f "$@"
}

这里假设命令的语法如下:

ss_mv /var/www/myfile /var/www/newdir/myfile

通过这种方式,从命令的第二部分提取目录路径/var/www/newdir,然后创建新目录(使用dirname标记以避免将myfile添加到正在创建的新目录中是很关键的)。

然后我们继续使用"$@"标记对整个字符串再次执行mv