Как переместить все файлы с именами, начинающимися со строки из списка?

Как переместить все файлы с именами, начинающимися со строки из списка?

У меня есть файл 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=""

Связанный контент