Bash: почему файл будет скопирован в последний каталог при вводе ‘cp hey foo *’?

#bash #command #cp

#bash #команда #cp

Вопрос:

Структура выглядит следующим образом

james /
hey / foo1 / foo2 / foo3

При вводе этой команды

cp hey foo*

Я получаю следующее уведомление

cp: пропуск каталога ‘foo1’
cp: пропуск каталога ‘foo2’

И файл hey копируется в каталог foo3.

Почему это происходит так? Почему hey был скопирован в каталог foo3, почему не в foo1 и foo2 ?

Комментарии:

1. Чего бы вы ожидали от этого? Поместите копию hey в каждое из имен каталогов, начинающихся с foo ?

2. Если это то, что вы хотите : for d in foo*/; do cp -- hey "$d"; done . Поскольку существует только один аргумент назначения для каждого вызова cp (проверьте справочную страницу!), Вам нужен один вызов для каждого назначения.

3. Да, я хочу скопировать hey в каталоги foo со всеми суффиксами. Спасибо за ваш комментарий, теперь я получил свой ответ.

Ответ №1:

когда вы делаете это:

 cp hey foo*
  

bash расширяет аргументы. В вашем случае командная строка расширяется до

 cp hey foo1 foo2 foo3
  

Последний аргумент — целевой файл / каталог. cp отказывается копировать каталоги, если -R/-r опция не установлена, отсюда и сообщения.

И hey файл копируется в foo3

cp или любая другая команда не может определить разницу между командной строкой с * и командной строкой с расширенными аргументами, в отличие от Windows cmd, например.

Если вам удастся передать фактический * символ в cp (например: cp foo* bar ), то cp будет проверен вызываемый файл foo* . В командах нет расширения механизма подстановочных знаков (некоторые есть в портах Windows, но это уже другая история)

Примечание: это не тот способ, которым его следует использовать:

  • Если вы знаете, что есть только каталог с foo префиксом, это может быть способом копирования файлов в нем, не зная точного имени каталога.
  • более классическое использование: cp *.txt foo

Примечание2: опасный случай: если у вас есть file1 и file2 и вы хотите скопировать их foo , и вы вводите cp file* , пропуская foo (или нажимая RETURN по ошибке), он будет скопирован file1 file2 (в оболочках, которые не разворачивают подстановочные знаки, чего не может быть).

В вашем случае, если вы хотите скопировать hey во все foo* каталоги, вам нужно выполнить цикл:

 for target in foo*
do
   cp hey "$target"
done
  

Комментарии:

1. Возможно, стоит вызвать (хотя это уже подразумевается в вашем ответе), который cp не может определить, какой расширенный аргумент был получен из какой части исходной командной строки, поскольку он не может сообщить, что какая-либо «исходная командная строка» даже существовала.

2. @CharlesDuffy я намекнул на это в своей второй заметке. Вы правы, я отредактирую.

3. кивок . Как я прочитал, OP хочет поместить одну копию hey в каждый из foo* каталогов, т. Е.. чтобы все они рассматривались как пункты назначения. Вы объясняете, почему это не работает, но несколько косвенно.

4. @CharlesDuffy: Типичная проблема XY, верно? 🙂 Я добавил способ сделать это в конце моего ответа. Наконец, лучше попытаться исчерпывающе объяснить эту классическую проблему.

5. @CharlesDuffy: спасибо за редактирование! Я, очевидно, не тестировал это!