Я не совсем уверен, как это сформулировать, и, возможно, поэтому я ничего не могу найти, но я хочу повторно использовать значения, перечисленные подстановочным знаком в команде. Это возможно?
Сценарий:
$ ls /dir
1 2 3
Содержимое / dir - это каталоги 1, 2 и 3.
$ cp /dir/*/file .
Приводит к копированию файла из / dir / 1 / dir / 2 и / dir / 3 сюда.
Что я хотел бы сделать, так это скопировать файлы в новое имя места назначения на основе подстановочного знака.
$ cp /dir/*/file ???-file
приведет к копированию / dir / * / file в 1-файл, 2-файл и 3-файл. Что я не могу понять, так это ???
часть, чтобы сообщить Bash, что я хочу использовать значения с подстановочными знаками.
Использование подстановочного знака в целевых сетях cp
ошибка:
cp: target `*-file' is not a directory.
Есть ли что-то еще в Bash, что можно здесь использовать?
В find
команда имеет {}
использовать с -exec
что похоже на то, что я ищу выше.
Моя первая мысль: вы, вероятно, слишком усложняете эту проблему. Однако это разрешимо.
Вы можете сделать что-то подобное с помощью безумного цикла bash:
for i in /dir/*/file
do
j=${i%/file}
k=${j#/dir/}
cp $i %k-file
done
который использует пару bash строковые операторы для извлечения номера исходного каталога.
Я гарантирую, что есть несколько более эффективных способов сделать это, именно это и пришло в голову.
ls /dir |while read dirname; do cp -v /dir/"$dirname"/file "$dirname"-file ; done
zsh% autoload zmv # should be done for you, noting it just in case
zsh% zmv -C '(*)/file' '$1-file'
zmv - это функция оболочки, часто используемая через alias mmv='noglob zmv -W'
для еще более простого вызова, но в этом случае вы хотите использовать обычное, плюс -C для копирования вместо перемещения.
Как сказал Фил, вам нужно перебрать элементы расширенного подстановочного знака; извлечение интересующего вас бита (в вашем примере имя каталога в dir /), а затем действие на это извлеченное значение.
У меня есть другой быстрый и хитрый способ сделать это ниже. Очевидная ошибка заключается в том, что это сломается, если в именах файлов есть пробелы, но это не единственная ошибка.
andromeda:tmp polleyj$ find dir/ ?-file
dir/
dir//1
dir//1/a
dir//1/b
dir//1/c
dir//2
dir//2/d
dir//2/e
dir//2/f
dir//3
dir//3/g
dir//3/h
dir//3/i
1-file
2-file
3-file
andromeda:tmp polleyj$ for f in dir/*; do
> i=$(basename $f)
> mv dir/${i}/* ${i}-file/
> done
andromeda:tmp polleyj$ find dir/ ?-file
dir/
dir//1
dir//2
dir//3
1-file
1-file/a
1-file/b
1-file/c
2-file
2-file/d
2-file/e
2-file/f
3-file
3-file/g
3-file/h
3-file/i
andromeda:tmp polleyj$
В большинстве дистрибутивов (с использованием util-linux's переименовать):
rename /file -file /dir/*/file
На Debian и Ubuntu (вините Debian):
rename.ul /file -file /dir/*/file
Или используя переименование Perl (в Debian и Ubuntu я не знаю, где его найти в других дистрибутивах):
rename 's,(\d+)/file,$1-file,' */file
Это некрасиво:
find -type f -exec sh -c 'cp "{}" "$(basename "$(dirname "{}")")-$(basename "{}")"' \;
Если я понял вашу точку зрения, mcp делает то, что вы хотите.
Подсказка: mcp принадлежит ммв пакет.
Ваша ситуация:
$ tree . ├── dir │ ├── 1 │ │ └── foo │ ├── 2 │ │ └── bar │ └── 3 │ └── baz └── dst 5 directories, 3 files
Решение:
$ mcp -v 'dir/*/*' 'dst/#1-#2' dir/1/foo -> dst/1-foo : done dir/2/bar -> dst/2-bar : done dir/3/baz -> dst/3-baz : done $ tree . ├── dir │ ├── 1 │ │ └── foo │ ├── 2 │ │ └── bar │ └── 3 │ └── baz └── dst ├── 1-foo ├── 2-bar └── 3-baz 5 directories, 6 files
Я думаю, это должно быть в основном самоочевидным
Здесь происходит то, что mcp принимает из и к аргумент. В из Аргумент может содержать подстановочные знаки оболочки (*,?), соответствующие набору файлов. Эти совпадения имеют обратную ссылку в к узор в упорядоченном порядке как №1, №2, №3 и так далее.