У меня есть большое количество папок с названным файлом genome.txt
то, что я должен cp
в ту же папку. Я пытаюсь выяснить, как я могу сделать это так, файлы похожи genome1.txt
, genome2.txt
, и т.д. Я ищу простое решение этого.
Это может быть сделано с простым сценарием оболочки, который использует find ...|while read var ; do ... done
структура (очень распространенный имея дело с именами файлов). Сценарий удара ниже воздействует на текущий (самый важный) каталог и берет отдельный аргумент для места назначения.
#!/bin/bash
find -name "genome.txt" -print0 | while IFS= read -r -d '' path
do
base=$(basename --suffix=".txt" "$path")
new_path="${1%/}"/"$base"$counter".txt"
echo "$path" "$new_path"
counter=$(( $counter +1 ))
done
>>> ПРИМЕЧАНИЕ <<<: использование сценария echo
просто для тестирования. Когда Вы удовлетворены получающимися путями, заменой echo
с mv
перемещать все имена файлов или cp
скопировать все имена файлов.
Пример:
bash-4.3$ tree
.
├── destination
├── dir1
│ └── genome.txt
├── dir2
│ └── genome.txt
├── dir3
│ └── genome.txt
└── move_enumerated.sh
4 directories, 4 files
bash-4.3$ ./move_enumerated.sh ./destination
./dir2/genome.txt ./destination/genome.txt
./dir3/genome.txt ./destination/genome1.txt
./dir1/genome.txt ./destination/genome2.txt
Этот сценарий может быть далее улучшен для создания этого более общим, где пользователь может указать имя файла, главный каталог для пересечения, и место назначения все как параметры командной строки:
#!/bin/bash
find "$2" -name "$1" -print0 | while IFS= read -r -d '' path
do
base=$(basename --suffix=".txt" "$path")
new_path="${3%/}"/"$base"$counter".txt"
echo "$path" "$new_path"
counter=$(( $counter +1 ))
done
Тестовый прогон:
bash-4.3$ ./move_enumerated.sh "genome.txt" "./testdir" "./testdir/destination"
./testdir/dir2/genome.txt ./testdir/destination/genome.txt
./testdir/dir3/genome.txt ./testdir/destination/genome1.txt
./testdir/dir1/genome.txt ./testdir/destination/genome2.txt
По всему сценарию использует command | while read variable ; do ... done
структура. Это - очень общий подход, и он часто используется, чтобы не иметь дело с ls
и трудные имена файлов, которые могут повредить сценарии.
На левой стороне канала мы имеем find
команда, которая берет каталог в качестве аргумента (и если это не дано, GNU find
то, которое используется в Linux, принимает .
- текущий рабочий каталог). Другие опции включают -name
который является определенным именем файла, которое мы ищем, и -print0
который используется для вывода результатов, как разграничено через непечатаемый \0
символ. Это часто используется, чтобы не разделять на новой строке или других символах, потому что те символы могут потенциально появиться в самом имени файла и в результате повредить сценарий.
На правой стороне канала мы имеем while IFS= read -r -d '' ; do . . . done
структура. while
цикл с read
встроенная оболочка часто привыкла к реальному stdin
вход, который в этом случае прибывает из канала. IFS=
-r
и -d ''
необходимы, чтобы гарантировать, чтобы мы получили имена файлов безопасно и распознали, что каждый объект разграничен с \0
.
Остальная часть сценария довольно легка. Мы извлекаем базовое имя использования файла basename
команда. Так как в этом случае мы имеем дело конкретно с известным расширением и ожидаем иметь единственную точку в имени файла, мы можем использовать --suffix=".txt"
разделять ту часть, уезжая genome
часть. Мы затем создаем новый путь к файлу через присоединение к месту назначения, базовому имени и переменной счетчика. Заметьте, что мы используем расширение параметра с "${3%/}"
аргумент (папка назначения) в нашем улучшенном сценарии. Это сделано, чтобы гарантировать, что независимо от того, добавил ли пользователь /
символ в командной строке ( ./destination
или ./destination/
), мы извлекаем только пустое имя каталога и присоединяемся к нему через различный /
с базовым именем. Заметьте также это counter
переменная не установлена первоначально, таким образом, первое имя файла, которое мы получаем, будет просто genome.txt
После, чем, переменная счетчика будет увеличена и таким образом создана и обнаружится, когда мы будем иметь дело с другими именами файлов.
Для большего количества информации считайте Имена файлов и Пути в Shell: Как сделать это Правильно.