У меня есть файл strings.txt
со списком строк:
GCA_001677475.1
GCA_003410275.1
GCA_002310615.1
GCA_000007405.1
GCA_000219515.3
И у меня есть много файлов в каталоге с именами типа:
GCA_000005845.2_ASM584v2_protein.faa
GCA_000006925.2_ASM692v2_protein.faa
GCA_000007405.1_ASM740v1_protein.faa
GCA_000007445.1_ASM744v1_protein.faa
GCA_000008865.2_ASM886v2_protein.faa
GCA_000009565.2_ASM956v1_protein.faa
Мне нужно переместить только те файлы, имена которых начинаются с шаблона из strings.txt
. До сих пор я пробовал использовать xargs
с mv
:
cat strings.txt | xargs -I % mv %*faa ./Data
Но mv
не видит %*faa
как регулярное выражение и пытается найти файлы с таким же именем (и, конечно, не может найти ни одного). Я также пробовал использовать, ls
но это работает так же:
cat strings.txt | xargs -I {} ls {}*faa
Так как же мне это сделать?
решение1
xargs bash -O nullglob -c '
for prefix do
set -- "$prefix"*.faa
[ "$#" -gt 0 ] && mv -- "$@" ./Data
done' sh <strings.txt
Используется xargs
для пакетной передачи строк strings.txt
встроенному bash
скрипту.
Для каждой строки встроенный bash
скрипт проверяет, есть ли в текущем каталоге имена файлов, соответствующие строке (добавляя *.faa
в конец для создания шаблона), и если да, то они перемещаются в каталог Data
, который, как предполагается, уже существует.
Параметр nullglob
оболочки устанавливается для встроенного скрипта, чтобы убедиться, что если сконструированный шаблон ненетсоответствует чему-либо, шаблон удаляется (а не сохраняется нерасширенным).
Я проверяю явно, совпадает ли шаблон, потому что в вашем примере есть строки, которые не совпадают ни с одним из показанных вами имен файлов. Это делается путем установки списка позиционных параметров в результат расширения glob и последующей проверки того, $#
больше ли нуля длина списка ( ).
Очевидно, вы могли бы сделать это и без xargs
этого:
shopt -s nullglob
while IFS= read -r prefix; do
set -- "$prefix"*.faa
[ "$#" -gt 0 ] && mv -- "$@" ./Data
done <strings.txt
Это все равно будетнеудачаесли одна из ваших префиксных строк совпала со многими тысячами имен файлов ( mv
командная строка стала бы слишком длинной). Если это так, вы, возможно, использовали бы
shopt -s nullglob
while IFS= read -r prefix; do
set -- "$prefix"*.faa
if [ "$#" -gt 0 ]; then
printf '%s\n' "$@" | xargs sh -c 'mv -- "$@" ./Data' sh
fi
done <strings.txt
Это предполагает, что ни строки префиксов, ни имена файлов не содержат встроенных символов новой строки.
решение2
Вот возможное решение:
cat strings.txt | xargs -I '%' find . -type f -name "%*" -exec mv -t your_path {} +
Перемещено GCA_000007405.1_ASM740v1_protein.faa
, это единственное совпадение.
решение3
Нет необходимости в xargs
чем-то сложном. Если все файлы находятся в одном каталоге, то должно быть достаточно сделать:
$ while read string; do
mv "$string"_* ./Data;
done < strings.txt
Или, если ваши имена могут начинаться с буквы «а» -
или в них могут присутствовать другие странные символы, используйте:
$ while read -r string; do
mv -- "$string"_* ./Data;
done < strings.txt
решение4
Быстрый и грязный хак:cat strings.txt| xargs -i sh -c 'mv {}* your/path/'>&/dev/null
Менее правильный хак:export dir=$(ls -1); cat strings.txt| xargs -i sh -c 'grep "^{}" <<<$dir && mv {}* your/path'; dir=""