Home > Back-end >  Cannot expand xargs placeholder for stat command
Cannot expand xargs placeholder for stat command

Time:11-12

Intro

Let's say I have this folder structure

images/
  image1.png
  image1.webp
  image1.avif
  image2.jpg
  image2.webp
  image2.avif

And I want to run through each image and show its respective size in a following format:

images/image1.png: 12333 | webp: 6300 | avif: 3400

images/image2.jpg: 15983 | webp: 8497 | avif: 1248

I am currently stuck at this attempt:

find -E images -regex ".*\.(png|jpg)" | xargs -I_ echo 'function getimgsize () { echo $(stat -c "%s" "$1"); }; srcimg="_"; srcimgnoext=$(echo "$srcimg" | sed -E "s/.jpg|.png//g"); srcimgsize=$(getimgsize "$srcimg"); webpsize=$(getimgsize "$srcimgnoext.webp"); avifsize=$(getimgsize $srcimgnoext.avif); echo "$srcimg: $srcimgsize | webp: $webpsize | avif: $avifsize"' | sh

The script above yields:

stat: cannot stat '_': No such file or directory
stat: cannot stat '_.webp': No such file or directory
stat: cannot stat '_.avif': No such file or directory
stat: cannot stat '': No such file or directory
stat: cannot stat '_': No such file or directory
stat: cannot stat '_.webp': No such file or directory
stat: cannot stat '_.avif': No such file or directory
_ :
function getstat () { echo ; }; srcimg=_; srcimgnoext=_; srcimgsize=; webpsize=; avifsize=; echo _ :

Question

How to fix the script so that it yields the proper results in a proper format?

CodePudding user response:

xargs -I_ echo 'function getimgsize ()... 

Ugh, so convoluted. If you find yourself in such a situation, and you are using Bash, it means something is wrong. Just write the function and export it.

getimgsize() {
    stuff to do with "$1"
    srcimg="$1"
}
export -f getimgsize
input | xargs -n1 bash -c 'getimgsize "$@"' _

Do not write complicated code in single quotes. Use shellcheck to check for common mistakes. Do not use function name() - just name(). The xargs stuff | sh looks odd, I think xargs sh -c 'stuff' is commonly preferred. Do not pass arguments inside strings xargs -I {} sh -c 'echo {}' - prefer to use positional arguments xargs -I {} sh -c 'echo "$1"' - {}. Do not use echo $(stuff). Just stuff, it already outputs it.

Is there really any value in using xargs here? Just loop it.

getimgsize () { stat -c "%s" "$1"; }
find -E images -regex '.*\.(png|jpg)' |
while IFS= read -r srcimg; do
    srcimgnoext=$(<<<"$srcimg" sed -E 's/\.(jpg|png)$//')
    srcimgsize=$(getimgsize "$srcimg")
    webpsize=$(getimgsize "$srcimgnoext.webp")
    avifsize=$(getimgsize "$srcimgnoext.avif")
    echo "$srcimg: $srcimgsize | webp: $webpsize | avif: $avifsize"
done

CodePudding user response:

I have a script similar to this, for comparing different compression formats. Here's a short adaption:

find . -mindepth 1 -maxdepth 1 -type f \
\( -name '*.png' -o -name '*.jpg' \) -print0 |
while IFS= read -rd '' file; do
    file=${file#./}
    name=${file%.*} ext=.${file##*.}
    list=$name

    for i in "$ext" .webp .avif; do
        size=$([[ -e "$name$i" ]] && stat -c %s "./$name$i")
        list ="$i: ${size:--} | "
    done

    echo "${list% | }"
done |
column -t |
sort -k1,1

Looks like:

dragon.jpg:  111626  |  .webp:  -       |  .avif:  -
foo1.png:    20088   |  .webp:  5000    |  .avif:  295040
foo2.png:    12254   |  .webp:  13320   |  .avif:  74036
foo3.png:    19600   |  .webp:  -       |  .avif:  101388
foo4.png:    160800  |  .webp:  353883  |  .avif:  25792
foo5.png:    397100  |  .webp:  325920  |  .avif:  59249

It prints a dash if the corresponding file doesn't exist. You can change the delimiters etc.

  • Related