如何在另一个文件夹中执行命令,而不重复文件夹路径?


73

有没有一种聪明的方法来执行复制和移动操作或命令来复制文件,而不必在同一文件夹中先执行cd,然后执行mv

例如,我必须运行以下命令:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

请注意,我要将文件移动到的目录是相同的,但是我必须再次输入整个路径,有时它会令人讨厌。我很想知道是否还有另一种方法可以不必重新放置整个路径,因为该操作将在同一路径中完成。


9
我简直不敢相信这有这么多赞成票。这是一个重复的unix.stackexchange.com/questions/35782/...unix.stackexchange.com/questions/66889/...
user13107

13
@ user13107有很多方法可以提出问题,包括不同的措词。而且,如果您不知道答案是否被称为“括号扩展”,则可能无法立即找到答案。
slhck

2
@ user13107他们在不同的站点上,所以不能重复
user151019 2013年

1
马克,谢谢,我不知道关于重复的规则。@slhck是的。我明白。我很沮丧,因为我在Unix.SE上的问题以重复的形式被关闭,而这个问题如此受欢迎。
user13107 2013年

3
@ user13107,这就是在正确的网站上发布的内容
Samuel Edwin Ward

Answers:


125

只需使用括号扩展

mv /folder1/folder2/folder3/{file.txt,file-2013.txt}

这相当于编写:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

当然,括号扩展允许您提供更多参数。你甚至可以通过范围到它,比如建立了几个测试文件夹,您可以运行mkdir test_{a..z},并开始猛砸4,您可以创建零填充序列以及,如touch foo{0001..3},创建foo0001foo0002foo0003。该击黑客维基有一对夫妇为你的例子的文章。

如果必须使用两个不同的命令,cd请先使用子外壳,然后使用该外壳,如@Ignacio的answer所示


5
我不知道brace扩展情况,谢谢!
Valter Silva

我尝试了一下,但似乎没有用:meniac ~: mv /tmp/f1/f2/f3/f4/f5/f6/{file.txt, file2.txt} mv: cannot stat ``/tmp/f1/f2/f3/f4/f5/f6/{file.txt,': No such file or directory
Valter Silva

5
您确定您正在使用Bash(如中的一样)/bin/bash,并且您不在/bin/shshebang或其他不支持花括号扩展的shell 中的脚本中吗?如果您跑步set,您是否会SHELLOPTS遏制braceexpand
slhck

22
请注意,file.txt,和之间不应有空格file2.txt
slhck

9
您可以使其更短,以防止出现不变的部分出现错别字:mv /folder1/folder2/folder3/file{,-2013}.txt
Jan Fabry

74

在子外壳中运行该操作。

( cd /folder1/folder2/folder3 && mv file.txt file-2013.txt )

工作目录的更改不会传播到父外壳。


11
+1:我喜欢那种比支撑扩展技巧更易携带的外壳(整洁,但不易携带)
Olivier Dulac

@Olivier,是什么让您认为支撑扩展不是可移植的?您想到的是哪个外壳不支持它?
亚历克西斯

5
POSIX未指定@alexis Brace扩展,因此非便携式“按设计”。ashdashksh88更不用说老Bourne shell中的例子并不支持它炮弹。
jlliagre

@jlliagre您提到的哪个shell完全符合POSIX?这意味着即使是POSIX,他们也不会进行大括号扩展。ksh88在POSIX批准之前;您应该至少升级到ksh93。Linux中只有两个人会关心的是灰烬和破折号,因为它们被用于一些小型嵌入式发行版(busybox,iirc?)和应急磁盘中。
卡兹(Kaz)

2
@Kaz我在乎shell命令的可移植性,它们是否交互是无关紧要的。当然,您当然可以不必管它,但请接受人们的其他看法。您始终使用bash或支持barce-expansion的shell的事实并不意味着每个人都是这样。
jlliagre

21

如果想要聪明,这里是bash 历史扩展

mv /folder1/folder2/folder3/file.txt !#:1:h/file-2013.txt

我自己不会使用此功能,因为我无法记住。我偶尔会使用等效vim,但是几乎每次都必须查找它。


11

您可以设置一个变量。当然,这样做的副作用是保留变量。

D=/folder1/folder2/folder3; mv $D/file.txt $D/file-2013.txt

并且,当然,您可以通过将整个命令行放入subshel​​l中来避免变量留下的副作用(D="/folder1/folder2/folder3"; mv "$D"/file.txt "$D"/file-2013.txt),或者只需unset在末尾添加命令即可。(我将引号作为“最佳做法”添加;如果您习惯于始终使用引号,那么当包含特殊字符的路径名出现时,您将不必停下来挠头。)
Scott

@Scott如果要使用子shell消除副作用,则执行a cd比设置变量要容易。不是很多容易,我承认。
艾萨克·拉比诺维奇

2

我喜欢其他解决方案,但是这里有另一个解决方案,实现为带有bash数组的脚本,推送,弹出:

#!/bin/bash
set -e
# from http://stackoverflow.com/a/246128/178651
script_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# paths relative to the script
relative_paths=( \
path1 \
path2 \
path3 \
path4
)

for relative_path in "${relative_paths[@]}"
do
  pushd "$script_path/$relative_path" > /dev/null 2>&1
  pwd
  mv filename1 filename2
  # could do other stuff in this directory...
  popd > /dev/null 2>&1
done

pushd "$script_path" > /dev/null 2>&1
# could do other stuff in same directory as script...
popd > /dev/null 2>&1

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.