이 패턴으로 이름이 지정된 수백 개의 이미지가 있습니다.
file-001.gif
file-002.gif
file-003.gif
...
Magick을 사용하여 총 크기가 950kb를 초과하지 않는 한 각 이미지 세트를 추가하고 싶습니다.
그런 다음 총 크기가 950kb 미만이면 다음 배치를 처리합니다.
이것이 쉘 스크립트에서 달성될 수 있습니까?
답변1
글쎄, 나는 이것이 내가 본 것 중 최악의 단 한 줄이라고 확신하지만 그것이 효과가 있을 것이라고 생각합니다. 느슨하게 기반https://askubuntu.com/questions/878948/how-do-i-generate-a-running-cumulative-total-of-the-numbers-in-a-text-file
sed $(echo 3+`ls -la | tee out/filesWithSizes.txt | awk '{print $5}' | awk '{total += $0; $0 = total}1' | sed 's/$/ < 950000/' | bc | grep -o '1' | wc -l`|bc )q out/filesWithSizes.txt | tail -n +4
이 광기를 설명하겠습니다.
ls -la
모든 파일과 크기를 가져오는 데 사용됩니다 .
tee
나중에 참조할 수 있도록 해당 정보를 저장하고 파이프라인에 저장하는 데 사용됩니다.
5열 인쇄용 awk
(예: 크기)
more를 사용하여 awk
누적 합계를 생성하고 각 디자인이 정렬되도록 보장합니다(나중에 중요해질 것입니다).
sed
줄 끝을 바꾸는 데 사용되므로 < 950000
기본적으로 문자열을 추가합니다.
bc
이러한 표현식을 평가하고 부울 값(예: 0 또는 1)으로 변환하는 데 사용됩니다 .
grep -o
1을 포함하는 줄만 인쇄하는 데 사용됩니다 .
누적 합계는 설계별로 정렬되므로 출력을 계산할 수 있고 함께 붙여넣을 수 있는 파일 수를 순서대로 알 수 있습니다.
이 부분은 으로 끝났습니다 wc -l
. 처음에는 a 플래그 없이는 작동할 수 없었기 때문에 3 + 파일 목록 출력의 중지 지점을 얻기 위해 ls
방금 계산한 숫자를 에코했습니다.bc
그런 다음 sed
명령 대체를 사용하여 이전에 echo를 사용하여 계산한 줄 수 이후에 저장된 파일 목록의 내용과 크기 출력을 중지합니다.
tail
마지막으로 해당 파일의 헤더가 아닌 첫 번째 줄에서 출력을 시작하는 데 사용됩니다 .
그러면 함께 연결할 수 있는 모든 파일 목록이 표시됩니다. 처리된 모든 파일을 이동하고 디렉토리에 더 이상 파일이 없을 때까지 거대한 oneliner를 계속해서 다시 실행하십시오.
답변2
일괄 추가해야 하는 이미지가 950kB보다 작은 개체로 끝나는 경우 단일 이미지 파일은 동일한 크기 구분을 초과할 수 없습니다.
첫 번째 단계: 해당 파일과 해당 크기를 모두 바이트 단위로 나열합니다.
$ find -L /path/to/directory -maxdepth 1 -type f -name "*.gif" -size -950k \
-exec sh -c '\ls -Lgo "$1" | tr -s " " | cut "-d " -f3,7-' sh {} \;
그러면 발견된 모든 파일의 이름과 해당 크기가 발견된 순서대로 한 번에 한 줄씩 화면에 인쇄됩니다. 주요 징후 find
는 다음과 같습니다.
-L
:심볼릭 링크를 따르고 링크 자체가 아닌 링크 대상에 대한 정보를 표시합니다. 이를 원하지 않으면 를-H
사용하십시오.-maxdepth 1
: 드롭될 수 있는 검색을 수행합니다.1
수준, 떨어지는 것에서/path/to/directory
. 필요에 따라 번호를 수정합니다. 자세한 내용은 을 참조하세요man find
.
적어도 bash
5.0 구현 에서는 find
킬로바이트(kiB) 단위로 작동하는 것 같습니다. 즉, 위의 경우 950*1024바이트 이하의 크기를 가진 파일을 찾습니다. 컷오프 크기를 950KB(950000B)로 설정해도 문제 없습니다. 그냥 사용하세요 -size 927730c
. Debian 배포판에서는 이 문제가 2016년에 해결된 것으로 보이므로 계속 사용할 수 있습니다 -size 950k
.
"크기"모호한 속성일 수 있습니다. OP에 더 많은 정보가 부족하기 때문에 다음을 사용할 수 있다는 사실도 포함했습니다.할당된 총 블록 크기발견된 각 파일에 대해. 이것이 당신이 원하거나 필요한 것이라면 다음을 수행하십시오.
$ find -L /path/to/directory -maxdepth 1 -type f -name "*.gif" -size -950k \
-exec sh -c '\ls -Ls -C1 "$1"' sh {} \;
여기서 얻는 크기 수치는 저장 매체의 블록 크기에 따라 달라집니다.
2 단계magick
: 쉘 스크립트를 통해 batch_append.sh
이전 출력을 한 번에 처리합니다 . 이미지 파일은 나열된 순서대로 첨부하되, 결과물의 무게는 950kB를 초과할 수 없습니다. 이 명령의 출력은 find
다음과 같이 배열을 채우는 데 사용됩니다.
$ cat batch_append.sh
#!/usr/bin/bash
sdir=/path/to/directory
size=0
nas_idx=0 # next append start (nas) index (idx)
cnt=0
declare -a b
IFS=$'\n' read -d '' -a a < <(find -L "$sdir" -maxdepth 1 -type f -name "*.gif" -size -950k -exec sh -c '\ls -Lgo "$1" | tr -s " " | cut "-d " -f3,7-' sh {} \; 2>/dev/null)
num=${#a[@]}
for (( i=0; i<num; i++ )); do
(( size+=$(echo "${a[$i]}" | cut "-d " -f1) ))
if [ "$size" -gt 950000 ] ; then
(( size-=$(echo "${a[$i]}" | cut "-d " -f1) ))
(( i-=1 ))
#echo "$size" for files from "$(( nas_idx+1 ))" to "$(( i+1 ))" # testing
#echo "${b[@]}" # testing
magick "${b[@]}" append appended_$(( nas_idx+1 ))_$(( i+1 )).gif
nas_idx=$(( i+1 ))
size=0 # reset 'size' variable to start new append batch
cnt=0
unset b
else
b[cnt]=$(echo "${a[$i]}" | cut "-d " -f2-)
(( cnt++ ))
fi
if (( i==num-1 )); then
# last append batch
#echo "$size" for files from "$(( nas_idx+1 ))" to "$(( i+1 ))" # testing
#echo "${b[@]}" # testing
magick "${b[@]}" append appended_$(( nas_idx+1 ))_$(( i+1 )).gif
unset b
fi
done
printf '\n %d files were processed.\n' "$num"
exit(0)
결론:
- 실행하기 전에 스크립트를 실행 가능하게 만드십시오.
chmod ug+x batch_append.sh
- 스크립트를 한 번만 실행하면 됩니다.
- 스크립트가 아직 전달되지 않았습니다
magick
. - 프로덕션 환경의 경우 포함해야 할 문제가 많이 있습니다.
- 호스트에 다중 코어가 있고 많은 수의 파일을 처리해야 하는 경우 병렬 실행을 예약하여 스크립트를 개선할 수 있습니다.
- 파일은 도착하자마자 일괄 처리됩니다. 즉,
find
cmd가 파일을 계산할 때입니다. 이는 검색 플래그의 수와 이를 연속적으로 정렬하는 방법에 따라 달라집니다find
.