저는 Linux Ubuntu 18.04 및 20.04를 사용하고 있습니다.
Ripgrep( rg
)은 다음과 같이 일치 항목이 포함된 파일에 대한 경로 목록을 출력할 수 있습니다.
# search only .txt files
rg 'my pattern to match' -g '*.txt' -l
# long form
rg 'my pattern to match' --glob '*.txt' --files-with-matches
출력은 다음과 같습니다:
path/to/file1.txt path/to/file2.txt path/to/file3.txt
등.
tree $(dirname $PATH)
그런 다음 각 경로에서 다른 명령을 실행하여 일치하는 파일이 포함된 디렉터리의 모든 파일 목록을 가져오고 싶습니다 . 어떻게 해야 하나요?
xargs
그게 답의 일부가 될 수도 있을 것 같은데요 ? 그러나 xargs
이와 같은 파이프라인으로 시작하면 마지막으로 인쇄된 파일만 처리하는 것 같습니다.
rg 'my pattern to match' -g '*.txt' -l | xargs -0 -I {} dirname {}
참고: Too를 사용하여 시연할 수 있다면 ripgrep 이 grep
없는 사람들에게도 유용할 수 있습니다.ripgrep
설치가 매우 쉽습니다..
인용하다:
답변1
GNU 시스템에서는 다음과 같이 보일 수 있습니다:
rg -g '*.txt' -l0 'my pattern to match' | # list files NUL-delimited
xargs -r0 dirname -z -- | # takes dirnames
LC_ALL=C sort -zu | # remove duplicates
xargs -r0 tree --
둘 다 dir/file.txt
일치 하면 둘 다에서 실행 dir/subdir/file.txt
되므로 내용이 두 번 표시됩니다 .tree
dir
dir/subdir
dir/subdir
귀하의 생각은 정확합니다. xargs
which is 명령을 사용하여 바이트 문자열을 매개변수 목록으로 변환하여 명령에 전달하고 -0
which를 사용하면 임의의 매개변수 목록을 전달하는 가장 안정적인 방법이 됩니다.
xargs -0
입력은 매개변수 목록이 NUL 문자(0바이트)로 구분되는 형식일 것으로 예상됩니다. 이 형식으로 파일 목록을 인쇄 하려면-0
/ 옵션이 필요합니다 .--null
rg
- GNU는
dirname
호출당 여러 인수를 처리할 수 있으므로-I{}
이를 사용하는 대신 모든 인수²를 전달합니다. 또한 파일 목록이 비어 있을 때 이를 전혀 호출하지 않고-r
NUL로 구분된 디렉터리를 인쇄하는 옵션 자체도 GNU에 해당합니다.dirname
-z
dirname
dirname
- 각 파일에는 접두사가 붙지 않으므로 파일 이름 앞에 s가 붙는 문제를 피하기 위해
rg
파일 목록을 인수로 전달하는 명령에./
옵션 구분 기호를 사용하는 것이 중요합니다.--
-
간단히 말해서, 값이 NUL이 아닌 바이트 시퀀스(예: 파일 경로 또는 임의의 명령 인수)일 수 있는 목록의 경우 NUL로 구분된 레코드를 교환 형식으로 사용하는 도구와 도구 간에 프로그래밍 방식으로 목록을 전달하려고 합니다. 인간 형식으로만 사용자에게 피드백을 제공합니다(여기서 트리 출력 tree
).
GNU가 아닌 시스템에서는 zsh
쉘을 사용하여 다음을 수행할 수 있습니다:
files=( ${(0)"(rg -g '*.txt' -l0 'my pattern to match')"} )
typeset -U unique_dirs=( $files:h )
(( $#unique_dirs )) && tree -- $dirs
또는 한 번에(일치하는 파일이 하나 이상 있다고 가정):
tree -- ${(u)${(0)"$(rg -g '*.txt' -l0 'my pattern to match')"}:h}
u
( nique u
) 교체됨 typeset -U
. 매개변수 확장 플래그는 NUL에서 분할 0
하도록 지시하는 방법입니다 . zsh
또는 IFS=$'\0'
토큰화를 설정하고 사용할 수 있습니다(따옴표가 없는 인수 확장 중에 수행됨).
IFS=$'\0'
tree -- ${(u)$(rg -g '*.txt' -l0 'my pattern to match'):h}
GNU 유틸리티나 GNU 유틸리티가 모두 없는 경우 zsh
언제든지 다음을 사용할 수 있습니다 perl
.
rg -g '*.txt' -l0 'my pattern to match' |
perl -MFile::Basename -MList::Util=uniq -0 -e '
@dirs = uniq(map {dirname$_} <>);
exec "tree", "--", @dirs if @dirs'
¹ 이것은 명령 인수에 나타날 수 없는 유일한 문자/바이트 값입니다(인수는 execve()
시스템 호출에서 NUL로 구분된 문자열로 전달되기 때문입니다). 그러나 파이프를 통해 공급되는 바이트 스트림에는 나타날 수 있으므로 간단하고 명확합니다. 임의의 매개변수를 분리하는 방법입니다. -0
GNU 구현에 대한 비표준 확장이지만 xargs
이제 다른 많은 구현에서도 찾을 수 있습니다.
² 또는 적어도 한 번의 통화에 들어갈 수 있는 만큼, dirname
필요한 만큼만 통화하십시오.
답변2
업데이트: 새로운 최종 답변:
sort -zu
null로 구분된( -z
) 목록이 정렬되고 중복 항목이 제거됩니다 .
rg 'my pattern to match' -0 -g '*.txt' -l \
| sort -zu \
| xargs -0 -I{} -- dirname {} \
| xargs -0 -I{} -- tree {}
이전 답변 세부정보:
이 답변 아래의 의견을 참조하십시오. 여기서 내 대답은 그다지 강력하지 않습니다@Stéphane Chazelas의 또 다른 답변.
-
아래 내 대답은 처음에 공백이나 다른 공백이 있는 파일 이름을 올바르게 처리하지 못하며 대시( )로 시작하는 파일 이름 도 처리하지 않습니다 . 내 답변 의견은 다음과 같습니다.
@StéphaneChazelas, 귀하의 모든 의견이 의미가 있습니다. 당신의 대답은 더 강력합니다.
--null
(-0
)를 withrg
및 with와 함께 사용하는 것이xargs
확실히 더 강력합니다. 그것도 사용할 것이다--
. 나는 파일에 공백이 포함되어 있지 않거나-
대시( )로 시작하는 파일이 없는 git 저장소에서 이 명령을 실행하고 있기 때문에 이러한 사항에 대해 별로 신경 쓰지 않는 것 같습니다 . 여러 경로가 있는 한 번의 호출 대신 여러dirname
& 호출에 대해서는tree
이를 알고 있지만 동의합니다. 부분적으로는 완전히 변경할 필요 없이 쉽게 확장하고 더 많은 파이프와 명령을 추가할 수 있다는 답변을 원하기 때문입니다.
그럼 이 두 가지 답변을 살펴보세요. 그는 기술적으로 더 낫지만 내 것은 현재 내 목적에 "충분히 좋습니다". 질문에 대한 원래 예제는 최소한의 변경으로도 작동한다는 점을 지적합니다. 전임자:
# I should have done this (add `-0` to `rg` and add `--` to `xargs`):
rg 'my pattern to match' -0 -g '*.txt' -l | xargs -0 -I {} -- dirname {}
# instead of this:
rg 'my pattern to match' -g '*.txt' -l | xargs -0 -I {} dirname {}
이것@Stéphane Chazelas의 답변그리고 내 질문 아래의 댓글(여기에는 ripgrep 작성자가 직접 만든 것도 포함됩니다.! ) 모두 도움이 되었고 다음 사항을 알아내는 데 도움이 되었습니다. 이는 가장 간단하기 때문에 가장 간단하고 최선의 답변이라고 생각합니다.
의 출력 경로 문자열은 rg
null로 끝나는 문자열이 아니므로-0
xargs
명령 에서 제거(또는 반대로 rg
명령에도 추가합니다).그게 다야! 이제 괜찮아:
# THESE WORK to get the dirnames!
# (`--null`/`-0` are removed from both `rg` and `xargs`)
rg 'my pattern to match' -g '*.txt' -l | xargs -I {} dirname {}
# OR (same thing--remove the space after `-I` is all):
rg 'my pattern to match' -g '*.txt' -l | xargs -I{} dirname {}
또는 -0
명령에 또는 를 추가하여 경로 문자열을 강제로 null로 종료할 수 있으므로 이 방법도 작동합니다.--null
rg
# ALSO WORKS
# (`--null`/`-0` are ADDED to both `rg` and `xargs`; note that for
# both `rg` and `xargs`, `--null` is the long form of `-0`)
rg 'my pattern to match' -g '*.txt' -l --null | xargs --null -I{} dirname {}
tree
이제 확장을 통해 다음과 같은 모든 경로를 전달할 수 있습니다.
최종 답변:
rg 'my pattern to match' -0 -g '*.txt' -l \
| xargs -0 -I{} -- dirname {} \
| xargs -0 -I{} -- tree {}
그게 다야! 난 그냥 둘 중 하나가 필요해다음에 추가또는마이너스 -0
또는 두 호출 모두 --null
에서 일관성을 유지하고 여러 경로를 확인할 때 동일한 설명자를 기대합니다.rg
xargs
다음에 추가 -0
그러나 or는 --null
경로에 공백이나 기타 공백을 포함할 수 있기 때문에 더 좋고, add 도 대시( )로 시작하는 경로를 --
허용하므로 좋습니다 . -
그래서 이것이 제가 위에서 한 일입니다.
그러나 다른 답변도 참조하십시오. 또한 중복 항목을 정렬, 제거하고 기타 복잡한 문제를 처리할 수도 있습니다.
당신은 또한 볼 수 있습니다
- 제가
xargs
배운 내용과 예시는 다음과 같습니다.
키워드: xargs를 올바르게 사용하는 방법 xargs를 사용하여 grep 또는 ripgrep rg 출력 경로를 구문 분석합니다.