사람이 읽을 수 있는 경로 목록을 다른 명령으로 리디렉션하는 방법은 무엇입니까?

사람이 읽을 수 있는 경로 목록을 다른 명령으로 리디렉션하는 방법은 무엇입니까?

"사람이 읽을 수 있는 형식"(예 : 공백 locate없이)으로 경로 목록을 생성하는 것과 같은 명령 출력으로 작업할 때 해당 출력을 다른 명령으로 어떻게 리디렉션합니까?\

의 출력은 $ locate [something]공백이 포함된 경로를 생성하므로 공백이 포함된 경우 다른 프로그램에서 해당 경로를 사용할 수 없습니다. 예를 들어, 내가

$ du -h `locate *.doc`

이렇게 하면 공백이 포함된 모든 파일과 디렉터리에 오류가 발생합니다. (틱을 공백으로 감싸는 것은 작동하지 않습니다)

답변1

을 사용하는 구체적인 이유는 무엇입니까 locate? 이는 귀하가 요청한 작업을 수행하는 것으로 보입니다.

find . -type f -name '*doc' -exec du -h "{}" \;

즉, 만약 당신이정말locate또는 같은 도구를 사용하고 그 입력을 다른 프로그램에 매개변수로 전달하고 싶다면 일부 도구가 제공하는 구분된 출력과 입력을 find활용할 수 있습니다 . 둘 다 프로그래밍 방식 으로 더 친숙한 출력을 얻을 수 있는 옵션( 's 및 's )이 있습니다.NULlocatefindlocate-0find-print0xargs그것은 -0논쟁:

find . -type f -name '*doc' -print0 | xargs -0 du -h

locate -0 '*doc' | xargs -0 du -h

답변2

동일한 줄을 여러 명령에 전달하고 싶거나 전달해야 하는 경우 다음과 같이 작동합니다.

#!/usr/bin/env bash

T="${IFS}" # Save off the Internal Field Separator

IFS=$'\n' # Set it to newline.

while read file_line
do
        echo "--"
        echo "${file_line}"
        echo "--"
done <<< $(locate $1) 
IFS="${T}  # Set it back to the original IFS. 

포장해가는 것도 좋을 것 같아요어느""에 공백이 있을 수 있는 변수입니다.

답변3

명령 대체( $(...)또는 `...`구식 형식)를 따옴표로 묶지 않으면 Bourne과 같은 쉘에서 Split+glob(zsh에서만 분할)이 호출됩니다.

분할은 $IFS기본적으로 공백, 탭 및 줄 바꿈(zsh에서는 NUL)을 포함하는 특수 매개변수의 문자에 대해 수행됩니다. 이는 공백 문자가 포함된 파일 이름에 대해 명령이 작동하지 않는 이유를 설명합니다.

당신은 할 수 있습니다 :

(IFS='
' # split on newline only
set -o noglob # disable glob
du -hc -- $(locate '*.doc'))

그러나 개행 문자가 포함된 파일 이름이 있으면 여전히 실패합니다. 의 출력은 locate단순히 사후 처리가 불가능합니다.

대부분의 구현에는 파일 경로를 구분하여 출력하는 옵션이 locate있습니다 . NUL은 파일 경로에서 발생할 수 없는 유일한 바이트 값입니다. 즉, 출력이 사후 처리 가능함을 의미합니다. NUL로 분할하면 됩니다.-0NUL

안에 zsh:

IFS=$'\0'
du -hc -- $(locate -0 '*.doc')

또는 명시적인 NUL 분할 연산자를 사용하는 것이 더 좋습니다.

du -hc -- ${(0)"$(locate -0 '*.doc')"}

4.4+ 에서는 bash다음과 같을 수 있습니다.

readarray -td '' files < <(locate -0 '*.doc')
du -hc -- "${files[@]}"

그래도 여전히 두 가지 문제가 남아 있습니다.

  1. locate파일을 찾지 못하면 인수 du -hc --없이 실행됩니다. 즉, 현재 작업 디렉터리의 디스크 사용량을 알려줍니다.
  2. 반면에 많은 파일을 찾으면 시스템 호출 locate의 한계에 도달하여 결과를 얻을 수 있습니다 .execve()인수 목록이 너무 깁니다.오류.

다음을 수행하면 두 가지 문제를 모두 피할 수 있습니다.

locate -0 '*.doc' | xargs -r0 du -hc --

( -r그리고 -0GNU 구현의 비표준 확장인 것은 xargsGNU -h구현의 비표준 확장입니다 du).

그러나 이로 인해 새로운 문제가 발생합니다. 제한 을 해결하기 위해 여러 번 xargs실행되지만 이는 여러 줄을 얻게 되며 여러 번 하드 연결된 파일의 디스크 사용량이 여러 번 계산될 수 있음을 의미합니다.duexecve()total

덕분에 -r파일 을 찾지 못하면 du실행되지 않지만 locate이는 또한 줄을 얻지 못할 것임을 의미합니다 0 total.

최신 버전의 GNU에서는 du이러한 문제를 다음과 같이 해결할 수 있습니다.

locate -0 '*.doc' | du --files0-from=- -hc

이번에는 파일 목록이 인수 대신 파이프를 통해 전달되므로 인수 크기에 제한이 없습니다. 이는 또한 해당 목록을 저장하기 위해 많은 양의 메모리를 할당할 필요가 없으며 출력을 시작 du하자마자 작업을 시작할 수 있음 을 의미합니다.locate

관련 정보