Як виконувати команди в іншій папці, не повторюючи шлях папки?


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/…
користувач13107

13
@ user13107 Є багато способів задати питання, включаючи різні формулювання. І якщо ви не знаєте, що відповідь називається "розширення брекетів", ви, можливо, не зможете її знайти відразу.
slhck

2
@ user13107 вони знаходяться на іншому сайті, тому не дублюють
user151019

1
Марк, спасибі, я не знав цього правила щодо дублікатів. @slhck Так. Я розумію. Мене просто засмутило, оскільки моє запитання на Unix.SE закрилося як дублікат, і це стало таким популярним.
користувач13107

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, ви також можете створити послідовності з нульовим накладом, як у 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в якому є шебанг чи інша оболонка, яка не підтримує розширення дужок? Якщо ви біжите 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: Мені подобається той, більш портативний через оболонки, ніж трюк розширення дужок (який акуратний, але менш портативний)
Олів'є Дулак

@Olivier, чому ви вважаєте, що розширення брекетів не є портативним? Яку оболонку ви маєте на увазі, яка не підтримує її?
alexis

5
@alexis Brace розширення не визначено POSIX, тому воно не є портативним "по дизайну". ash, dash, ksh88Не кажучи вже про стару оболонці Bourne є прикладом оболонок , які не підтримують його.
jlliagre

@jlliagre Які із згаданих вами оболонок повністю відповідають POSIX? Це означає, що вони не мали б розширення дужок, навіть якщо це був POSIX. ksh88 був до ратифікації POSIX; вам слід оновити принаймні ksh93. Єдині двоє, хто в Linux би переймався, - це зола та деш, оскільки вони використовуються у невеликих вбудованих дистрибутивах (busybox, iirc?) Та рятувальних дисках.
Каз

2
@Kaz Мене хвилює переносимість команд оболонки, а те, чи вони є інтерактивними чи не має значення. Звичайно, ви, безумовно, вільні не турбуватися про це, але прийміть, що люди думають інакше. Те, що ти завжди використовуєш bash або оболонку, яка підтримує барсе-розширення, не означає, що так у кожного.
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 безпосередньо відповідає на питання найпростішим можливим способом, але Вальтеру також подобається відповідь автопопу, тож ось такий, що йде по тих же лініях;

pushd /folder1/folder2/folder3/; mv file.txt file-2013.txt; popd
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.