Когда cp
получает более двух аргументов, последний принимается в качестве целевого каталога, а остальные - как файлы для копирования туда.
cp
не знает, что вы использовали подстановочный знак: подстановочные знаки расширяются оболочкой до того, как команда их увидит. Таким образом, даже если cp
имел какую-то возможность для нескольких целей, он не мог использовать этот синтаксис.
Вам понадобится петля. В оболочках типа Bourne:
(ret=0
for dir in myfolder*/constant/; do
cp foo.txt "$dir" || ret=$?
done
exit "$ret")
Задача $ ret
- в конце сообщать о любых сбоях cp
в статусе выхода.
Если вам нужно переименовать все файлы, имя которых содержит \
, вы можете сделать:
for file in *\\*; do
dir="$(dirname -- "${file//\\/\/}")"
filename="${file##*\\}"
mkdir -p -- "$dir"
mv -- "$file" "$dir"/"$filename"
done
for file in *\\*
:Глоб *\\*
соответствует любому имени файла или каталога в текущем каталоге, имя которого содержит \
. Поскольку \
также является escape-символом, нам нужно экранировать его, чтобы он рассматривался как литерал. Вот почему мы не можем просто использовать *\*
.
Затем это будет перебирать все файлы и каталоги, имя которых содержит \
, сохраняя каждый из них как $file
.
dir="$(dirname "${file//\\/\/}")"
:${file//\\/\/}
напечатает текущее имя файла, заменив все \
на /
. Экранирование \\
и\/
)необходимо, так как \
и /
являются специальными символами. dirname
печатает каталог, в котором содержится файл. Например, dirname /path/to/file
вернет /path/to
. Следовательно, $dir
будет целевым каталогом, в который мы хотим переместить этот файл.
filename=${file##*\\}
:имя файла, при этом все до последнего \
удалено. Это фактическое имя файла, и оно будет сохранено как $filename
.
mkdir -p "$dir"
:создать целевой каталог и всех его родителей. -p
заставляет mkdir
создавать родительские каталоги (без него mkdir foo/bar
не будет работать, если foo/
уже не существует ), а также заставляет игнорировать ошибки об уже существующем каталоге.
mv "$file" "$dir"/"$filename"
:последний шаг, переместите файл в нужное место.