awk:你如何使用新行构建字符串变量?

时间:2017-05-24 08:04:50

标签: linux bash awk busybox

我正在尝试执行以下操作:

ls -l对文件夹的结果:

-rw-rw-r--   1 root  root  100  May 23 09:45 filename1
-rw-rw-r--   1 root  root  200  May 23 09:45 filename2
-rw-rw-r--   1 root  root  500  May 23 09:46 filename3

现在我想通过awk传递这个来执行以下操作:

800 bytes, files:
filename1
filename2
filename3

到目前为止,我可以通过awk来添加字节:

output=`ls -l /some/folder/ | awk 'START {total = 0}; {total += $5} END{print total}'`

这个简单的提法:800

现在我想开始构建输出字符串,所以我试图得到一个文件名列表(我觉得列9美元),我这样想:

output=`ls -l /some/folder/ | awk 'START {total = 0; files=""}; {total += $5 files="\n" files $9} END{print total "files:" files}'`

echo $output提供以下内容:

800 filename1 filename2 filename3

我希望它显示:

800
filename1
filename2
filename3

我不明白为什么线条没有分成新线?

3 个答案:

答案 0 :(得分:2)

ls -l | awk 'NR > 1 {s+=$5; f=f"\n"$NF} END{print s,f}'

忽略ls -l输出中的第一行(NR > 1)。所有行中的5th字段(文件大小)都会添加到变量s中。文件名附加到变量f(由换行符分隔)。在END区块中,打印sf

<强>示例:

AMD$ ls -l
total 12
-rw-r--r-- 1 root root 165 May 24 08:23 ff
-rw-r--r-- 1 root root 165 May 24 08:23 gg
-rw-r--r-- 1 root root 165 May 24 08:23 hh

AMD$ ls -l | awk 'NR > 1 {s+=$5; f=f"\n"$NF} END{print s,f}'
495
ff
gg
hh

如果您想将其保存到变量中并稍后打印出来:

var=$(ls -l | awk 'NR > 1 {s+=$5; f=f"\n"$NF} END{print s,f}')
echo "$var"

答案 1 :(得分:2)

当您在shell中引用变量时,包含换行符的空格会被折叠,因此对您所做的事情的简单修复就是使用echo "$output"

尽管如此,我建议不要使用ls -l来获取您的文件名及其大小,因为该工具不是为解析而设计的。当你有一个有趣的文件名时,任何基于列的方法都会中断。

使用GNU stat允许您获取文件大小并控制输出,使用空字节\0使名称可以安全地解析:

stat --printf '%s\0%n\0' * | awk -v RS='\0' '
NR % 2 { total += $0; next } # add to total on odd lines, skip to next line
{ files[++n] = $0 }          # save file names on other (even) lines
END { print total, "bytes, files:"; for (i = 1; i <= n; ++i) print files[i] }'

如果您无法使用stat --printf,那么您可以使用stat -c并希望没有人在文件名中添加换行符:

stat -c '%s %n' * | awk '{ total += $1; files[NR] = substr($0, length($1) + 2) } 
END { print total, "bytes, files:"; for (i = 1; i <= NR; ++i) print files[i] }'

第一个字段包含名称,而该行的其余部分是文件名,因此substr用于获取该部分。

作为*的参数传递的stat被shell扩展为当前目录中的完整文件列表。您可以通过传递/path/to/dir/*或首先cd到目的地来获取另一个目录中的文件。您也可以使用循环,例如:

for dir in dir1 dir2 dir3; do
    ( cd "$dir" && stat -c '%s %n' * | awk '...')
done

在这里,我使用( subshell )作为循环每次迭代后返回原始目录的懒惰方式。

答案 2 :(得分:1)

要保留变量的结构,应该双引号。

示例:

多行变量:

x='hey
> there'

不引用:

echo $x
hey there

双引号:

echo "$x"
hey
there