AWK를 사용하여 텍스트 파일에 복사할 결과/값을 선택하는 스크립트

AWK를 사용하여 텍스트 파일에 복사할 결과/값을 선택하는 스크립트

bash 스크립트의 마지막 단계를 도와줄 수 있는 사람이 있나요? 제가 여기까지 올 수 있도록 도와주셨어요.

#!/bin/bash

find . -type f \
       -name '*.mp4' -o -name '*.mkv' \
    -o -name '*.avi' -o -name '*.mov' |
while read -r file
do 
    size=$(stat -c %s "$file")
    duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file")
    codec=$(ffprobe -v error -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$file")
    ratio=$(bc <<< "scale=2; $size / $duration")
    echo "$file: codec=$codec, size=$size, duration=$duration, ratio=$ratio" | tee -a /home/user/Downloads/logfile
    printf $ratio | awk '{print $1/1000}'| tee -a /home/user/Downloads/logfile
done

이제 모든 결과가 텍스트 파일로 들어갑니다. 그런데 비율이 다음보다 큰 파일만 선택하는 방법이 있나요?

@markp-fuso의 요청에 따라 몇 가지 사항을 명확히 했습니다.

$ratio의 몇 가지 예를 사용하여 질문을 업데이트하십시오.

$ratio의 숫자는 비디오 파일 크기(바이트)를 비디오 파일의 지속 시간(초)으로 나누어 생성됩니다. 숫자는 약 50k에서 1000k 사이입니다. 그래서 awk '{print $1/1000}'을 사용하여 50 - 1000 범위로 가져왔습니다.

그리고 컷오프/임계값으로 무엇을 사용하려고 하시나요? a) $ratio 의 값, b) awk 에서 생성된 값 또는 c) numfmt 호출 결과를 기준으로 필터링하시겠습니까?

좋은 점은 numfmt 호출을 사용하여 바이트를 메가바이트로 늘리고 싶다는 것입니다. 그런데 그게 잘렸어요. 따라서 제거할 수 있습니다. 원하는 결과가 나올 때까지 작동합니다.

./file1.mp4: codec=h264
aac, size=54886926, duration=94.900000, ratio=578365.92
578.366
./file2.mp4: codec=vp9
aac, size=15147100, duration=108.159000, ratio=140044.74
140.045
./file3.mp4: codec=vp9
aac, size=22306731, duration=109.947000, ratio=202886.21
202.886

길이가 길기 때문에 인코딩/축소할 수 있는 비디오/오디오 파일을 찾는 데 이것을 사용하겠습니다. 따라서 높은 $ratio를 인코딩할 수 있습니다. 이 값은 스크립트에서 쉽게 조정할 수 있지만 약 200-400입니다. 코덱 효율성에 따라 다릅니다(사용된 코덱을 표시하기 위해 행을 추가했습니다).

그래서 결국 요구 사항을 충족하는 파일만 포함하는 텍스트 파일을 갖고 싶습니다. 이 경우에는 설정된 비율보다 큽니다. 나는 경험을 바탕으로 결정을 내릴 것입니다.

노트:가능하다면 읽을 수 없고(손상 등으로 인해) 값이 없는 파일을 텍스트 파일에 추가하면 좋을 것 같습니다.

비율을 200으로 설정했다고 가정하면 위의 3가지 예를 기반으로 txt 파일에는 다음이 포함되어야 합니다.

./file1.mp4: codec=h264
aac, size=54886926, duration=94.900000, ratio=578365.92
578.366
./file3.mp4: codec=vp9
aac, size=22306731, duration=109.947000, ratio=202886.21
202.886

어떤 도움이라도 대단히 감사하겠습니다.

건배

답변1

아마도 상단 근처에서 컷오프를 선언하십시오.

# We only care about files with ratios GREATER than this:
cutoff=200000

그런 다음 루프 하단 근처에서 and 명령을 테스트 및 명령문으로 while래핑합니다 .echoprintfif

    ...
    ratio=$(bc <<< "scale=2; $size / $duration")
    rc=$(bc <<< "$ratio > $cutoff")
    if [[ "$rc" == "1" ]]
    then {
        echo "$file: codec=$codec, size=$size, duration=$duration, ratio=$ratio"
        awk '{print $1/1000}' <<< "$ratio"
    } | tee -a /home/user/Downloads/logfile
    fi
done

답변2

요청한 문제를 해결하기 전에 먼저 스크립트의 다양한 문제를 해결해야 합니다. 첫째, find명령이 잘못되었습니다. 둘째, 개행 문자가 포함된 파일 이름의 경우 명령이 실패합니다.

귀하의 find오류는 옵션을 그룹화하지 않았기 때문입니다. 이는 귀하의 명령이 이름이 eg로 끝나는 디렉토리도 찾는다는 것을 의미합니다 .mov. 다음 디렉토리를 고려하십시오.

$ ls -lF
total 4
-rw-r--r-- 1 terdon terdon    0 Mar 18 18:37 'a bad'$'\n''file name.mp4'
drwxr-xr-x 2 terdon terdon 4096 Mar 18 18:38  foo.mov/

여기에는 파일(이름에 공백과 개행 문자가 포함됨)과 디렉터리가 포함되어 있습니다 foo.mov. 파일을 처리하기만 원하지만 find디렉터리도 반환합니다.

$ find . -type f -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' -o -name '*.mov' 
./foo.mov
./a bad?file name.mp4

모든 조건에 적용 하려면 -type f다음과 같이 그룹화해야 합니다.답변이전 질문과 관련하여:

$ find . -type f \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' -o -name '*.mov' \)
./a bad?file name.mp4

위에서 볼 수 있듯이 괄호로 그룹화하면( 셸에서 보호하려면 이스케이프 \(하거나 따옴표로 묶어야 함) 명령이 필요에 따라 파일만 찾을 수 있습니다. '('다음 문제는 줄 바꿈입니다. find인쇄 결과를 \0개행 문자 대신 NULL( ) 바이트 로 구분 하여 이 문제를 해결할 수 있습니다 . GNU find(Linux 시스템의 기본값)를 사용하여 이 작업을 수행할 수 -print0있으며 다른 찾기 구현에는 를 사용할 수 있습니다 -printf.

이러한 이름을 처리하지 않으면 다음 오류가 발생합니다.

$ find . -type f \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' -o -name '*.mov' \) | while read -r file; do ls -l "$file"; done
ls: cannot access './a bad': No such file or directory
ls: cannot access 'file name.mp4': No such file or directory

올바른 방법은 다음과 같습니다.

$ find . -type f \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' -o -name '*.mov' \) -print0 | while read -r -d '' file; do ls -l "$file"; done
-rw-r--r-- 1 terdon terdon 0 Mar 18 18:37 './a bad'$'\n''file name.mp4'

여기서는 필수는 아니지만 IFS=사용하는 것이 좋습니다. 바라보다이 답변예를 들어, 실제 작업은 입력 구분 기호로 NULL을 사용하도록 옵션에 지시하여 -d ''수행 됩니다.readread

마지막으로, 반환되는 여러 코덱을 처리할 수 있어야 합니다. 이는 적어도 제가 테스트한 파일에 대해서는 매우 흔한 일이기 때문입니다. 예를 들어:

$ ffprobe -v error -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 foo.mkv 
hevc
ac3
ass

ffprobe따라서 tr '\n' ','명령의 출력 등을 통해 개행을 제거하십시오.

$ ffprobe -v error -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 foo.mkv | tr '\n' ','
hevc,ac3,ass,$

(마지막 것은 $내 프롬프트로, 여기에 후행 개행 문자가 없음을 나타냅니다.)

이제 요약하면 이미 변수에 비율이 있으므로 필요한 것은 if해당 비율이 임계값을 초과하는지 간단히 확인하는 것입니다. 왜 두 개의 비율( $ratiosum ) 이 있는지 이해가 되지 않습니다 $ratio / 1000. 제가 보기에는 실제로 테스트한 비율을 사용하는 것이 더 합리적으로 보이지만 그것은 귀하의 결정입니다. 작업 스크립트는 다음과 같습니다.

#!/bin/bash

threshold=$1
if [ -z "$threshold" ]; then
  echo "No threshold given, using the default value of 200" >&2
  threshold=200
fi

logfile="/home/user/Downloads/logfile"

find . -type f \
  \( -name '*.mp4' -o -name '*.mkv' -o \
     -name '*.avi' -o -name '*.mov' \) -print0 | 
 while IFS= read -r -d '' file
 do 
    size=$(stat -c %s "$file")
    duration=$(ffprobe -v error -show_entries format=duration \
                       -of default=noprint_wrappers=1:nokey=1 "$file")
    codec=$(ffprobe -v error -show_entries stream=codec_name \
                    -of default=noprint_wrappers=1:nokey=1 "$file" |
              tr '\n' ',')
    ratio=$(bc <<< "scale=2; $size / $duration")

    # Check that a ratio was found, otherwise print an error
    if [[ -z "$ratio" ]]; then
      echo "No ratio found for '$file'" >&2
    else
      ## Not sure why you want two separate values for ratio but...
      ratio2=$(bc <<< "$ratio / 1000")

      if [[ $ratio2 -ge $threshold ]]; then
        printf '%s: codec=%s size=%s, duration=%s, ratio=%s\n' \
               "$file" "$codec" "$size" "$duration" "$ratio" | tee -a "$logfile"
        echo "$ratio2" | tee -a "$logfile"
      fi
    fi
done

이제 임계값을 매개변수로 사용하여(또는 기본값 200 없이) 실행할 수 있습니다.

script.sh 300

스크립트에 약간의 사소하고 대부분 외관상의 변경을 가하고 몇 가지 기본 오류 처리를 추가했지만 정확히 동일한 작업을 수행해야 합니다. 출력은 다음과 같습니다.

$ foo.sh 200
./file3.mkv: codec=h264,aac, size=764948534, duration=3488.131000, ratio=219300.40
219
./file7.mkv: codec=h264,aac, size=739550128, duration=3542.852000, ratio=208744.29
208
./file5.mkv: codec=h264,aac, size=688337512, duration=3439.637000, ratio=200119.23
200
./file1.mkv: codec=h264,aac, size=883534591, duration=3701.386000, ratio=238703.71
238
./file4.mkv: codec=h264,aac, size=828112726, duration=3769.898000, ratio=219664.49
219

관련 정보