목록에서 문자열로 시작하는 이름을 가진 모든 파일을 이동하는 방법은 무엇입니까?

목록에서 문자열로 시작하는 이름을 가진 모든 파일을 이동하는 방법은 무엇입니까?

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 확장 결과로 설정한 다음 목록의 길이( $#)가 0보다 큰지 테스트하여 수행됩니다.

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 

또는 이름이 a로 시작 -하거나 다른 이상한 문자가 포함될 수 있는 경우 다음을 사용하세요.

$ 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=""

관련 정보