fzf 프로젝트를 동적으로 업데이트

fzf 프로젝트를 동적으로 업데이트

저는 시스템에서 파일을 검색한 다음 각 파일에 대해 몇 가지 온전성 검사를 수행하는 스크립트를 작성 중입니다. 검사를 통과하면 fzf에 표시하고 싶습니다. fzf에서 항목을 클릭하면 프로그래밍 방식으로 파일을 실행하고 싶습니다.

지금까지 나는 다음을 가지고 있습니다 :

dir="/path/to/dir"

fd . $dir --size +1MB | while read -r line; do
    file_type=$(file -b "$line")
    echo "$line" | fzf
    if [[ "$file_type" == "data" ]]; then
        echo "$file_type"
    fi
done

기본적으로 지정된 디렉터리에서 1MB보다 큰 파일을 검색합니다. 각 파일에 대해 file 명령을 실행하고 명령 출력이 "data"를 반환하는지 확인합니다. 그렇다면 fzf 목록에 추가하고 싶습니다. 그런 다음 항목을 클릭하면 응용 프로그램을 사용하여 전체 경로로 파일을 실행하고 싶습니다. 예: myapp /path/to/file/selected/in/fzf.

지금까지의 문제는 fzf 블록과 내가 루프의 목록을 채울 수 없다는 것입니다. 정말로 모든 것을 배열에 먼저 추가한 다음 fzf로 파이프해야 합니까? 이상적으로 이는 병렬로 발생해야 합니다. 즉, 검색이 완료될 때까지 기다리지 않고 검색이 진행 중인 동안 동적으로 새 항목을 추가하고 싶습니다.

또한 나중에 선택한 파일을 실행하는 방법도 모르겠습니다. 누군가 나를 도와줄 수 있나요?

답변1

fzf당신이 생각하는 방식을 방해하지 않을 것입니다. 목록에 동적으로 추가할 수 있습니다. 다음 예에서 이를 확인할 수 있습니다( pv설치되지 않은 경우 먼저 설치).

find / | pv -qlL 1 | fzf

pv초당 한 줄을 출력하는 이 줄이 표시되며 차단 fzf없이 선택 항목을 위아래로 이동할 수 있습니다.

코드의 문제는 루프 fzf내에서 실행되고 있다는 것입니다 while read …. 각 행에 대해 fzf해당 행만 가져오는 별도의 코드를 실행합니다 . 루프는 fzf완료된 후에만 계속될 수 있습니다. 그러므로 더 읽기를 거부하는 것이 아니라 fzf더 읽기를 거부하는 것입니다. fzf루프 내부에 있다는 것입니다 .

기본적으로 다음과 같은 것을 원합니다.

find … | data_filter | fzf

그중에는 data_filter행을 필터링하는 코드가 있습니다. 쉘 루프일 수 있습니다.

find … | while IFS= read -r line; do …; done | fzf

필터로서 루프는 필터링하고 싶지 않은 모든 행(및 해당 행만)을 표준 출력으로 인쇄해야 합니다. 이름이 지정된 쉘 함수일 수 있습니다 data_filter. 귀하의 경우 이것이 올바른 기능입니다.

data_filter() {
   while IFS= read -r line; do
   [ "$(file -b "$line" 2>/dev/null)" = data ] && printf '%s\n' "$line"
   done
}

그런 다음 이것은 파이프의 필터로 사용됩니다.

find … | data_filter | fzf이제 우리는 잘 작동하고 선택한 경로 이름을 인쇄하는 파이프를 갖게 되었습니다. 파일에 대해 특정 작업을 수행하려면 다음 명령 중 하나를 사용하십시오.

  • find … | data_filter | fzf | xargs …, xargs전체 줄을 있는 그대로 읽도록 구성됩니다. GNU의 경우 xargs실행하려는 도구가 다음과 같은 경우 ls -l:

    find … | data_filter | fzf | xargs --no-run-if-empty -d '\n' -I{} ls -l {}
    

    하지만 xargs기본적으로 따옴표를 해석하고 다른 작업(예: 분할)을 수행하므로 이러한 상황에서 사용하려면 해당 옵션을 잘 알아야 합니다. 나는 그것을 마스터한 적이 없으며 xargs여기서 최고의 옵션 세트를 사용하고 있는지 확신할 수 없습니다. 내 요점은 다음과 같습니다. 이와 같은 간단한 호출은 … | fzf | xargs ls -l많은 경우에 중단됩니다.

  • f="$(find … | data_filter | fzf)""$file", 원하는 곳 어디에서나 사용하세요. 한 가지 장점은 종료 상태를 알 수 있다는 것입니다 fzf. 이론적 단점은 $()후행 줄 바꿈이 제거된다는 것입니다. 실제로 우리의 경우 후행(또는 임의) 개행 문자가 있는 경로 이름은 어쨌든 잘 전달되지 않습니다 data_filter | fzf.

    예:

    f="$(find . | data_filter | fzf)"
    status="$?"
    [ "$status" = 0 ] && ls -l "$f"
    

파이프라인의 모든 도구는 줄 바꿈을 사용하여 항목을 구분하므로 줄 바꿈이 있는 경로 이름은 코드를 손상시킵니다.


줄바꿈이 포함된 경로 이름을 처리하려면 전체 파이프라인에서 (줄바꿈으로 끝나는 대신) Null로 끝나는 항목을 사용하도록 해야 합니다.

  • 먼저 find … -print0(또는 이와 동등한 fd명령)이 필요합니다. 일부 구현에서는 find이를 지원하지 않습니다 -print0( -exec printf '%s\0' {} +교체 가능).

  • 그러면 새 필터 기능은 다음과 같아야 합니다.

    data_filter0() {
       while IFS= read -r -d '' line; do
       [ "$(file -b "$line" 2>/dev/null)" = data ] && printf '%s\0' "$line"
       done
    }
    
  • 다음 번에 사용하세요 fzf --read0 --print0.

  • 마침내 xargs -r0 …. (대안은 $()번거롭기 때문에 자세히 설명하지 않겠습니다. 이 경우에는 이것이 선호됩니다 xargs -r0.) 이러한 옵션은 이식 가능하지 않으며 xargs지원할 수도 있고 지원하지 않을 수도 있습니다. 보너스로 xargs -r0객관식도 잘 작동합니다 fzf -m.

파이프라인 예:

find . -print0 | data_filter0 | fzf -m --read0 --print0 | xargs -r0 ls -l

참고 사항 및 유용한 링크:

  • 일반적으로 필터를 내장할 수 있습니다 find …(감사합니다 find -exec). 당신이 사용하고 싶어하는 것 같고 fd도구에 대해 잘 모르기 때문에 그렇게하지 않았습니다 .

  • 항목을 일찍(즉, find필터가 완료되기 전) 선택하면 fzf파이프라인의 나중 항목이 find종료되기 전에 종료될 수 있습니다. 필터는 fzf쓰기를 시도한 후에만 더 이상 존재하지 않는다는 것을 알 수 있습니다. 마찬가지로 find쓰기를 시도한 후에 알 수 있습니다.이 답변). 이는 find작업이 필요 이상으로 오래 걸릴 수 있음을 의미하며, 이로 인해 셸이 스크립트의 다음 명령을 계속 진행하지 못하게 됩니다(또는 대화형인 경우 프롬프트가 표시되지 않게 됩니다). 백그라운드에서 일부 부분을 실행할 수 있습니다.

    ( find . -print0 | data_filter0 & ) | fzf -m --read0 --print0 | xargs -r0 ls -l
    

    find종료 후 필터 작동이 중지되지는 않지만 fzf전체 라인이 중지되지는 않습니다. 쉘은 ls작업을 완료한 후 즉시 이동합니다. 백그라운드 프로세스는 조만간 종료됩니다.

  • 올바른 인용. 귀하의 질문에 인용된 내용이 없습니다 $dir.

  • printf더 나은가요 echo?.

  • 이해하다IFS= read -r line.

  • Bash에서 널 바이트를 사용하는 방법은 무엇입니까?

관련 정보