无法扩展 stat 命令的 xargs 占位符

Cannot expand xargs placeholder for stat command

简介

假设我有这个文件夹结构

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

我想 运行 查看每张图片并按以下格式显示其各自的大小:

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

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

我目前被困在这个尝试中:

find -E images -regex ".*\.(png|jpg)" | xargs -I_ echo 'function getimgsize () { echo $(stat -c "%s" ""); }; 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

上面的脚本产生:

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 _ :

问题

如何修复脚本以使其以正确的格式产生正确的结果?

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

呃,好绕。如果您发现自己处于这种情况,并且您正在使用 Bash,则说明有问题。写个函数导出就行了

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

不要用单引号写复杂的代码。使用 shellcheck 检查常见错误。不要使用 function name() - 只需 name()xargs stuff | sh 看起来很奇怪,我认为 xargs sh -c 'stuff' 通常是首选。不要在字符串 xargs -I {} sh -c 'echo {}' 内传递参数 - 更喜欢使用位置参数 xargs -I {} sh -c 'echo ""' - {}。不要使用 echo $(stuff)。就stuff,它已经输出了

在这里使用xargs真的有什么价值吗?只是循环它。

getimgsize () { stat -c "%s" ""; }
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

我有一个类似的脚本,用于比较不同的压缩格式。这是一个简短的改编:

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

看起来像:

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

如果对应的文件不存在,则打印破折号。您可以更改分隔符等。