Bash 如何将awk脚本更改为在Solaris上工作

Bash 如何将awk脚本更改为在Solaris上工作,bash,shell,awk,solaris,Bash,Shell,Awk,Solaris,下面的脚本是bin packing First-fit算法,该脚本在ubuntu Linux上正常运行,我可以调用bin_packing.awk,但是当我尝试在unix solaris上运行它时,我遇到了错误 bin\u packing.awk: function first_fit(v, file) { # find first bin that can accomodate the volume for (i=1; i<=n; ++i) { if (b[

下面的脚本是bin packing First-fit算法,该脚本在ubuntu Linux上正常运行,我可以调用bin_packing.awk,但是当我尝试在unix solaris上运行它时,我遇到了错误

bin\u packing.awk

function first_fit(v, file) {
    # find first bin that can accomodate the volume
    for (i=1; i<=n; ++i) {
        if (b[i] > v) {
            b[i] -= v
            bc[i]++
            cmd="mv "file" subdir_" i
            print cmd
            # system(cmd)
            return
        }
    }
    # no bin found, create new bin
    if (i > n) {
        b[++n] = c - v
        bc[n]++
        cmd="mkdir subdir_"n
        print cmd
        # system(cmd)
        cmd="mv "file" subdir_"n
        print cmd
        # system(cmd)
    }
    return
}
BEGIN{ if( (c+0) == 0) exit }
{ first_fit($1,$2) }
END { print "REPORT:"
    print "Created",n,"directories"
    for(i=1;i<=n;++i) print "- subdir_"i,":", c-b[i],"bytes",bc[i],"files"
}
这将创建一个文件列表,其前面的文件大小以字节为单位。值c是目录可以具有的最大大小(以字节为单位)。上述值c=100000只是一个示例,这将创建如下输出:

...
mv file_47 subdir_6
mv file_48 subdir_6
mv file_49 subdir_5
mv file_50 subdir_6
REPORT:
Created 6 directories
- subdir_1 : 49 bytes 12 files
- subdir_2 : 49 bytes 9 files
- subdir_3 : 49 bytes 8 files
- subdir_4 : 49 bytes 8 files
- subdir_5 : 48 bytes 8 files
- subdir_6 : 37 bytes 5 files
如果我尝试在Solaris上运行它,它会显示以下错误,并且根据反馈-printf是GNU特性,因此它在非GNU版本的find中不可用

在Solaris上使用
nawk
(新awk)或
/usr/xpg4/bin/awk
(POSIX awk)
awk
是原始的遗留版本,使用Perl收集与find相同的信息-printf:

以下是解:

$ find . -type f -name '*.pdf' -print | perl -lne '$,=" "; @s=stat $_; print $s[7],$_, $s[2]' | nawk -v c=5000000 -f bin_packing.awk

要保存缺少的--printf find功能的问题,可以尝试使用:

find . -type f -iname '*pdf' -exec stat --printf="%s %n\n" {} \; \
| awk -v c=100000 -f bin_packing.awk

该脚本实际上相当危险——例如,如果文件名为
$(rm-rf~)
,使用包含该脚本的命令运行
system()
,则会删除所有文件<代码>系统()。(
mv“$file”“$other_file”
在bash中是安全的,因为shell不会将扩展结果解析为语法,但是当您将名称传递到预扩展的shell中时,您不会获得这些安全性)…坦白地说,您的脚本只是进行字典查找和整数运算,如果您有一个最新版本的bash,那么可以在本机bash中实现它,而不需要awk;如果您没有最近的bash,那么它可能非常容易作为一个perl脚本(这也会给您一个本机
stat
调用,以便能够查找大小)。这个特定的awk错误消息意味着您正在运行旧的、损坏的awk(/bin/awk-Solaris上的默认值)。永远不要用那个awk,因为它,嗯,旧的,坏的。在Solaris上,请改用/usr/xpg4/bin/awk(如果有的话,也可以使用xpg6)。有人可能会突然出现并说“或纳克”-忽略这个建议,纳克比旧的、坏的awk更好(有时被命名或化名为
oawk
)但是它仍然比我推荐的xpg*AWK更老,更不符合POSIX标准。如果要使用该脚本生成mv和mkdir命令,至少要确保正确引用文件名和目录名。将每一个
cmd=“mv”file“subdir_u2;”i
或类似于
cmd=“mv\047”file“\047\047\subdir_2;i”\047”
和每一个
cmd=“mkdir subdir_2;”n
更改为
cmd cmd=“mkdir\047subdir_2;_2;”n“\047”
,将所有内容用单引号括起来(由
\047
\047生成)。要查看区别:
echo'$(回声世界)“|awk”{cmd=“echo”$0;system(cmd)}”
输出
hello world
while
echo'$(echo“hello world”)”|awk'{cmd=“echo\047”$0”\047;system(cmd)}
输出
$(echo“hello world”)
,也就是说,前者将字符串公开给shell进行解释/执行,而后者则不公开,因此更安全。很好,但您的解决方案不适用于solaris
-printf
是GNU功能,因此它在非GNU版本的find中不可用,solaris也不理解`-iname`仅
-name
,我使用Perl收集了与find的
-printf
相同的信息,以及它的工作原理
$ find . -type f -name '*.pdf' -print | perl -lne '$,=" "; @s=stat $_; print $s[7],$_, $s[2]' | nawk -v c=5000000 -f bin_packing.awk
find . -type f -iname '*pdf' -exec stat --printf="%s %n\n" {} \; \
| awk -v c=100000 -f bin_packing.awk