альтернатива sh для избиения CP {файл, файл}

В сценарии, если я поместил #!/bin/bash наверху, это будет хорошо работать:

cp directory/{foo,bar} destination

Однако с sh, это даст ошибку 'никакой такой файл или каталог'. В sh там другой путь состоит в том, чтобы выполнить ту же конечную цель с одной командой?

5
задан 28 January 2020 в 13:27

2 ответа

Поскольку Вы наблюдали, не все расширение фигурной скобки поддержки оболочек.

Путь 1: Два отдельных тракта (т.е. запись префикса дважды)

Если Ваша цель состоит в том, чтобы действительно только сделать это в одной команде, простой путь:

cp directory/file1 directory/file2 destination

cp управляйте поддерживает несколько исходных аргументов, сопровождаемых целевым аргументом. На самом деле это - то, что происходит с командой, которая работает на Вас в Bash. Bash выполняет расширение фигурной скобки, которое преобразовывает команду, которую Вы использовали в один показанный выше. Таким образом, когда Вы работаете cp directory/{file1,file2} destination в Bash, cp команда никогда не видит фигурных скобок.

Команда как этот проста и легка для понимания. Я предлагаю рассмотреть это.

Путь 2: переменная для префикса

Но если Ваша цель состоит в том, чтобы не повторять себя, то Вы могли бы предпочесть не делать это тот путь, особенно если directory на самом деле длинный тракт. В конце концов, если бы необходимо отредактировать путь позже в сценарии, необходимо было бы внести изменения в оба случаев.

Можно сохранить directory (или что бы то ни было, по-видимому, более длинный путь, который является) в переменной оболочки:

dir='directory'
cp "$dir/file1" "$dir/file2" destination

$dir расширение параметра. Оболочка заменяет его значением, сохраненным в переменной dir. При использовании расширения параметра Вы не должны опускать двойные кавычки - кроме редкого случая, что Вы хотите, чтобы полевое разделение и globbing были выполнены. (Это относится к Bash также.)

Это - две команды, но если Ваша фактическая цель состоит в том, чтобы не повторять себя, которые могут быть тем, что Вы хотите. Вы могли записать

dir='directory'; cp "$dir/file1" "$dir/file2" destination

для создания его "одной командой" но это не короче, и это немного менее читаемо.

(Обратите внимание, что Вы не можете просто удалить ; там. Результатом выполнения была бы правильно построенная команда, но это не сделает то, что Вы хотите. Это работало бы cp команда, передавая названную переменную среды dir со значением directory в cp среда команды. Так как это - оболочка а не cp команда, которая расширяется dir, это не работало бы.)

Путь 3: cdig к префиксу

Если Ваш сценарий не делает ничего больше после выполнения этой операции, или не имеет значения, что текущий каталог для последующих команд, то если destination полный путь, можно использовать:

cd directory
cp file1 file2 destination

Но я не рекомендую, чтобы для сценариев, если Ваш сценарий не выполняет последующие действия, которые извлекают выгоду из того, чтобы быть выполненным из того каталога, или мог быть более кратко или просто записан, когда они выполняются из того каталога. Кроме тех случаев, когда каталог, от которого запущен скрипт, значим до цели сценария, полагаться на него может сделать сценарий тяжелее для обоснования о; кроме того, если cd команда успешно выполняется, но cp управляйте сбоями, получающиеся сообщения об ошибках могут быть менее, чем полностью освещающими. Вместо этого я упоминаю технику cdлуг к исходному каталогу, потому что это - полезный шаблон для интерактивного использования оболочки.

(Как Hannu указал, можно включить любое количество команд вместе внутри ( ) выполнять их в подоболочке и изменениях в среде оболочки, включая эффект cd, не сохранится после того, как команда работала. Это - широко полезная техника, и это был существенный пропуск, что я не упомянул это. Обратите внимание, однако, что это не смягчает проблем, касающихся наличия относительного пути для destination.)

Отметьте это если cd управляйте сбоями, другие команды будут все еще обычно работать. Это могло скопировать различные файлы, которые Вы не хотите скопированный (если существуют другие файлы с теми же именами в каталоге, который сценарий запускал от) или производил запутывающие сообщения об ошибках. Таким образом, можно предпочесть:

cd directory && cp file1 file2 destination

&& заставляет вторую команду работать только если первая команда, за которой следуют. Обратите внимание, что это все еще не отменяет эффект выполнения первой команды. После всего этого выполнения Вы все еще будете в directory, если Вы не выполнили его в подоболочке с ( ).

8
ответ дан 30 January 2020 в 23:29

Редактирование 1: После того, как вопрос был изменен, первая альтернатива больше не действительна, и вторая альтернатива изменяется 'file1 file2'-> 'панель нечто' и расширилась с дополнительными примерами.


Это работает на меня в sh с

cp directory/file[12] destination

и это должно работать на Вас также.

Более усовершенствованная альтернатива для цикла

for i in foo bar;do cp directory/"$i" destination;done

На это легко расширить, например,

for i in foo bar more files;do cp directory/"$i" destination;done

или

for i in dir1/foo* /dir2/bar*;do cp "$i" destination;done

или

for i in dir1/* /dir2/*;do cp "$i" destination;done

Редактирование 2: Вместо усовершенствованного использования конструкций cp стоит изучить и начать использовать rsync, который является инструментом с большим количеством встроенных функций для копирования локально или через сеть и указывающий, что скопировать.

Посмотрите man rsync

4
ответ дан 30 January 2020 в 23:29

Другие вопросы по тегам:

Похожие вопросы: