이 명령은 "일반" 이름이 dir1 mydir my-dir 등인 디렉토리에 대해 작동합니다.
ls | parallel 'echo -n {}" "; ls {}|wc -l'
각 디렉토리의 파일 수를 알려주세요.
그러나 공백이 있는 디렉터리(예: "내 디렉터리" 또는 긴 디렉터리 이름)의 경우 작동하지 않고 오류가 발생합니다.
공백을 인용/이스케이프하는 방법은 무엇입니까?
답변1
GNU Parallel은 공백을 처리하는 데 문제가 없습니다.
$ mkdir 'a b'
$ touch 'a b/c d'
$ ls | parallel 'echo -n {}" "; ls {}|wc -l'
a b 1
-0
이름에 \n이 포함되어 있으면 다음이 필요합니다.
$ mkdir 'a
b'
$ touch 'a
b/c
d'
# fails
$ ls | parallel 'echo -n {}" "; ls {}|wc -l'
$ parallel 'echo -n {}" "; ls {}|wc -l' ::: *
# works
$ printf "%s\0" * | parallel -0 'echo -n {}" "; ls {}|wc -l'
$ parallel -0 'echo -n {}" "; ls {}|wc -l' ::: *
ls
따라서 여러분이 보고 있는 것은 아마도 이상한 일을 했기 때문일 것입니다 ls --some-weird-option
. 대신 시도해 보십시오 ( 또는 위에 표시된 대로 \ls
사용 ).printf ... | ... -0
-0 ... ::: *
\ls | parallel 'echo -n {}" "; ls {}|wc -l'
(추신: 알고 계십니까 --tag
?
parallel --tag 'ls {}|wc -l' ::: *
)
답변2
parallel
아니요, xargs
또는 경로 이름을 앞뒤로 전달하는 복잡성:
shopt -s nullglob dotglob
for dir in */; do
set -- "$dir"/*
printf '%s:\t%s\n' "${dir%/}" "$#"
done
*
즉, 모든 디렉터리를 반복하고 각 디렉터리에서 전역 확장 이름의 수를 계산합니다.
위의 경우 일치하지 않는 패턴이 확장되지 않은 채로 남아 있는 것이 아니라 제거되도록 셸 옵션을 bash
설정했습니다 . nullglob
또한 dotglob
숨겨진 이름과 일치하도록 쉘 옵션을 설정했습니다.
쉘은 zsh
디렉토리(루프용)와 일반 파일(루프 본문)의 전역 일치를 필터링하는 동안 이 작업을 수행할 수 있습니다. 아래 코드에서 glob 한정자는 (ND/)
이전 콘텐츠가 *
shell 과 동일한 효과를 갖고 설정된 디렉터리에만 일치하도록 하며 nullglob
, 동일한 방식으로 이전 콘텐츠가 일반 파일에만 일치하도록 합니다.dotglob
bash
(ND.)
*
for dir in *(ND/); do
set -- $dir/*(ND.)
printf '%s:\t%s\n' $dir $#
done
너 이거 하고 싶어?재귀적으로, 계층 구조의 각 디렉터리에 있는 이름 수를 얻으려면 위의 내용을 삽입합니다 find
.
find . -type d -exec bash -O nullglob -O dotglob -c '
for dir do
set -- "$dir"/*
printf "%s:\t%s\n" "$dir" "$#"
done' bash {} +
bash
(위의 내용은 이 답변의 시작 부분에 있는 일반 루프와 약간 다릅니다. 이는 심볼릭 링크를 통해 액세스된 디렉토리의 이름을 계산하지 않기 때문입니다.) 또는,
find . -type d -exec zsh -c '
for dir do
set -- $dir/*(ND.)
printf "%s:\t%s\n" $dir $#
done' zsh {} +
답변3
cmd가 실행되는 하위 디렉터리에 있는 일반적인 파일 수를 나열하려고 한다고 가정하면 다음 코드 줄이 이를 수행합니다.
$ find . -maxdepth 1 -type d ! -name "." -print0 2>/dev/null \
| xargs -0 -I {} sh -c 'printf "%20s: %d\n" "{}" "$(find "{}" -maxdepth 1 -type f 2>/dev/null| wc -l)"'
출력 예:
./Maildir: 0
./.dvisvgm: 0
./.pyenv: 5
./.ipython: 0
./.ipynb_checkpoints: 3
./.tmux: 1
./.virtualenvs: 12
./seaborn-data: 2
./.local: 2
./bgpix: 12
./.vim: 7
...
2>/dev/null
find
테스트를 실행하는 데 사용하는 플랫폼에서 원치 않는 파일 액세스 문제를 피하기 위해 각 블록에 이것을 추가하고 있습니다 . cmd의 일부로 파일을 설정할find
때 이러한 파일 권한 문제가 발생할 것이라고 예상하지 않는다면 취소할 수 있습니다.- 또한 위에서 언급한 계산에만 관심이 있다는 가정에 맞게
$PWD
(현재 작업 디렉터리, 로 표시됨 ) 에 대한 모든 출력을 억제했습니다..
정기적인현재 하위 디렉터리의 파일입니다. - 처음부터 시작하여 전체 하위 디렉터리 트리의 일반 파일 수를 계산하려면 위의 첫 번째 블록에서 전역 옵션을
$PWD
생략하면 됩니다 (두 번째 블록에는 그대로 유지).-maxdepth 1
find
종속 솔루션 parallel
(아래)과의 유사성을 더 잘 강조하기 위해 위의 내용을 다시 작성할 수 있습니다.
$ xargs -0 -I {} sh -c 'printf "%20s: %d\n" "{}" "$(find "{}" -maxdepth 1 -type f 2>/dev/null| wc -l)"' \
< <(find . -maxdepth 1 -type d ! -name "." -print0 2>/dev/null)
위에 표시된 대로 parallel
치환 에 의존하여 xargs
아래와 같이 일부 따옴표를 이스케이프해야 합니다(출력은 이전과 정확히 동일함).
$ parallel -0 -I {} \
'sh -c "printf \"%20s: %d\n\" \"{}\" \"$(find {} -maxdepth 1 -type f 2>/dev/null | wc -l)\""' \
:::: < <(find -maxdepth 1 -type d ! -name "." -print0 2>/dev/null)
xargs
parallel
동일한 두 매개변수를-0 -I {}
사용 하여'sh -c "printf ..."'
실행될 쉘 명령은 작은따옴표 사이의 Bourne 쉘입니다.- 에 의해 도입된 병렬화에 대한 입력은 "cmd에서 시작하는 첫 번째 하위 수준의 모든 하위 디렉터리 찾기" 출력을 포함하는
::::
프로세스 대체 입력 파일입니다 .<(...)
$PWD
답변4
ls 대신 find를 사용하여 솔루션을 찾았습니다.
find * -type d -maxdepth 0 | parallel 'echo -n {}" "; ls {}|wc -l'