스크립트에서 절대 경로와 공백이 있는 경로의 모든 파일을 나열하는 방법

스크립트에서 절대 경로와 공백이 있는 경로의 모든 파일을 나열하는 방법

경로를 매개변수로 받아들이고 경로에 있는 모든 .mkv 파일을 처리하는 스크립트를 작성 중입니다. 경로는 절대 경로, 상대 경로 또는 단일 파일일 수 있습니다. 그러나 반복되는 파일의 절대 경로가 여전히 필요합니다.

지금까지 내가 한 일은 다음과 같습니다.

#!/bin/bash

path=$1
if ! [ -e "$path" ]; then
  path=$(pwd)
fi

find "$path" -type f -name '*.mkv' | sort | xargs realpath | while read file; do
  echo "Processing $file"
done

이는 경로 및/또는 파일에 공백이 없을 때 작동하지만 공백으로 인해 실패합니다.

올바른 접근 방식은 무엇입니까?

답변1

그리고 zsh:

#! /bin/zsh -
for file (${${1-.}:P}/**/*.mkv(ND.))
  print -r processing $file
  • ${1-.}Bourne 쉘에서와 같이 .if $1is not set로 확장됩니다(if $#== 0; if가 나쁜 인터페이스이고, $1is가 존재하지 않는 파일인 경우는 아닙니다. 이는 사용자에게 큰 놀라움이 될 것입니다).
  • ${param:P}realpath()해당 확장 으로 확장됩니다 . **/심볼릭 링크를 따르지 않고 .한정자는 선택만 하므로 모든 파일에 대해 동일한 작업을 수행할 필요가 없습니다.정기적인파일이므로 심볼릭 링크가 아닙니다.
  • **/모든 수준의 하위 디렉터리와 일치
  • Nnullglob, Ddotglob .에 대한 Glob 한정자정기적인오직.

답변2

모든 파일 대신 경로 자체를 전처리할 수 있습니다.

find "$(realpath -- "$path")" -type f -name '*.mkv' -exec printf 'Processing %s\n' {} +

printf실제로 파일로 수행하려는 작업으로 바꾸십시오 . +호출당 여러 파일을 처리할 수 있음을 나타냅니다. 그렇지 않은 경우 대신 를 사용하세요 \;.

답변3

Stephen의 의견에 동의합니다. 항상 -exec출력 후 처리를 선호합니다 find. 꼭 필요한 경우 항상 -print0명시적인 파일 이름 구분을 허용하는 도구를 사용하십시오. 입력의 파일 이름을 사용하는 대부분의 도구는 일종의 --null, --zero/ -z또는 -0플래그를 지원하여 입력을 0바이트 구분으로 해석하도록 합니다.

귀하의 경우에는 아마도 zsh를 선호할 것입니다. 그러나 bash를 고수하고 싶다고 가정하면 아무런 문제 없이 동일한 작업을 수행할 수 있습니다. sort어쨌든 와일드카드는 알파벳순으로 정렬되므로 생략해도 됩니다 . bash는 재귀적 글로빙을 수행할 수 있으므로 생략할 수 있습니다 find(zsh는 글로빙할 때 파일 유형을 제한할 수도 있고 bash에서는 실제로 파일성을 테스트해야 함 ). 어쨌든 파일을 처리하기 때문에 -f생략할 수 있습니다 . xargs:

#!/bin/bash
# Fail when something goes wrong!
set -e
# enable recursive globs, and don't fail when there's nothing there
shopt -s globstar
shopt -s dotglob
shopt -s nullglob

inpath="$1"
if ! [ -e "${inpath}" ]; then
  inpath="$(pwd)"
fi

for file in "${inpath}/**/*.mkv"; do
  # check whether regular file, skip if not
  [ -f "${file}" ] || continue
  fullpath="$(realpath -- "${file}")"
  echo  "Processing ${fullpath}" # Could / might prefer to use printf here instead
done

할 수 있는기본 정렬이 실제로 필요한 것이 아닐 경우를 대비해 항목을 다르게 정렬하세요. 교체해야 해

for file in "${inpath}/**/*.mkv"; do

비슷한 것

unsorted=( ${inpath}/**/*.mkv )
readarray -d '' -t sorted_files < \
    <(printf '%s\0' "${unsorted[@]}" \
        | sort -z --whateveroptions \
     )
for file in "${sorted_files[@]}" ; do

readarray전달된 문자열에 구분 기호를 설정하는 옵션이 있습니다 -d. 빈 문자열을 전달하면 0바이트가 구분 기호로 사용됩니다. readarray트림 -t(여기서는 필요하지 않지만 안전한 기본값인 것으로 확인됨)은 sort -z0바이트를 구분 기호로 사용합니다. "${arrayname[@]}"이 배열의 반복 가능한 요소 목록으로 확장되지만 요소에 공백과 줄 바꿈이 포함되어 있어도 안전하게 사용할 수 있습니다.

zsh에서는 와일드카드로 찾은 파일을 정렬할 수도 있습니다. 가능할 때마다 zsh를 사용하십시오.

관련 정보