Назад | Перейти на главную страницу

Расширение с подстановочными знаками

Я не совсем уверен, как это сформулировать, и, возможно, поэтому я ничего не могу найти, но я хочу повторно использовать значения, перечисленные подстановочным знаком в команде. Это возможно?

Сценарий:

$ 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 и так далее.