Как выполнить команды в другой папке, не повторяя путь к папке?


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

1
Марк, спасибо, я не знал это правило о дубликатах. @slhck Да. Я понимаю. Я был просто разочарован, потому что мой вопрос по Unix.SE был закрыт как дубликат, и этот стал настолько популярным.
user13107

3
@ user13107, вот что ты получаешь за публикацию на нужном сайте
Сэмюэль Эдвин Уорд

Ответы:


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}, и, начиная с Bash 4, вы можете также создавать последовательности с нулями, например, in touch foo{0001..3}, который создает foo0001, foo0002и foo0003. В Bash Hackers Wiki есть статья с несколькими примерами для вас.

Если вам нужно использовать две разные команды, сначала используйте подоболочку и cdтам, как в ответе @ Ignacio .


5
Я не знал о braceрасширении, спасибо!
Вальтер Сильва

Я пытался, и, кажется, не работает: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
Вальтер Сильва

5
Вы уверены, что используете Bash, как в /bin/bash, и у вас нет сценария, который есть /bin/shв shebang или какой-либо другой оболочке, которая не поддерживает расширение скобок? Если вы бежите set, вы SHELLOPTSсодержите braceexpand?
slhck

22
Обратите внимание, что между file.txt,и file2.txt. Не должно быть пробела .
slhck

9
Вы можете сделать его еще короче, чтобы избежать опечаток в той части, которая не меняется:mv /folder1/folder2/folder3/file{,-2013}.txt
Ян Фабри

74

Запустите операцию в подоболочке.

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

Изменение рабочего каталога не будет распространено на родительскую оболочку.


11
+1: мне нравится этот, более переносимый по всем оболочкам, чем трюк с расширением фигурных скобок (который аккуратный, но менее переносимый)
Оливье Дюлак

@ Оливье, с чего ты взял, что расширение скобок не переносимо? Какую оболочку ты имеешь в виду, что не поддерживает ее?
Алексис

5
Расширение @alexis Brace не указано в POSIX, поэтому оно не переносимо «по замыслу». ash, dash, ksh88Не говоря уже о старой оболочке Bourne являются примером оболочек , не поддерживающих его.
Jlliagre

@jlliagre Какие из упомянутых вами оболочек полностью соответствуют POSIX? Это означает, что у них не будет расширения скобки, даже если это был POSIX. ksh88 был до ратификации POSIX; Вы должны обновить по крайней мере до ksh93. Единственные два в Linux, о которых заботятся, это ash and dash, так как они используются в некоторых небольших встроенных дистрибутивах (busybox, iirc?) И аварийных дисках.
Каз

2
@Kaz Меня волнует переносимость команд оболочки и тот факт, что они интерактивны или нет, не имеет значения. Конечно, вы свободны не заботиться об этом, но, пожалуйста, примите, что люди думают иначе. Тот факт, что вы всегда используете bash или оболочку, поддерживающую расширение barce, не означает, что это дело каждого.
Jlliagre


11

Вы можете установить переменную. Конечно, у этого есть побочный эффект оставления переменных вокруг.

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

И, конечно же, вы можете избежать побочного эффекта от оставления переменной (ей), помещая всю командную строку в подоболочку: (D="/folder1/folder2/folder3"; mv "$D"/file.txt "$D"/file-2013.txt)или просто добавляя unsetкоманду в конце. (Я добавил кавычки как «лучшую практику»; если вы привыкли всегда использовать кавычки, вам не придется останавливаться и чесать голову, когда появляется путь, содержащий специальные символы.)
Скотт,

@ Scott, если вы собираетесь использовать подоболочку для устранения побочных эффектов, сделать это проще, cdчем установить переменную. Не намного легче, я признаю.
Исаак Рабинович

2

Мне нравятся другие решения, но вот еще одно, реализованное в виде скрипта с массивами bash, pushd, popd:

#!/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

1

Slhck напрямую отвечает на вопрос самым простым из возможных способов, но Вальтеру также нравится ответ autopop, так что вот такой же;

pushd /folder1/folder2/folder3/; mv file.txt file-2013.txt; popd
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.