Awk:如何用新行构建一个字符串变量?
Awk: How do you build a string variable with new lines?
我正在尝试执行以下操作:
文件夹 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 += } END{print total}'`
这个简单的给出:800
现在我想开始构建输出字符串,所以我试图获取文件名列表(我认为是 $9 列),我是这样尝试的:
output=`ls -l /some/folder/ | awk 'START {total = 0; files=""}; {total += files="\n" files } END{print total "files:" files}'`
echo $output
给出以下内容:
800 filename1 filename2 filename3
我想让它显示:
800
filename1
filename2
filename3
我不明白为什么这些行没有拆分成新行?
ls -l | awk 'NR > 1 {s+=; f=f"\n"$NF} END{print s,f}'
ls -l
输出中的第一行被忽略 (NR > 1
)。 5th
字段(文件大小)中的所有行都加在一个变量s
中。文件名附加到变量 f
(以换行符分隔)。在 END
块中,打印 s
和 f
.
示例:
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+=; f=f"\n"$NF} END{print s,f}'
495
ff
gg
hh
如果您想将其保存到变量中并稍后打印出来:
var=$(ls -l | awk 'NR > 1 {s+=; f=f"\n"$NF} END{print s,f}')
echo "$var"
White space,当你不在 shell 中引用你的变量时,包括换行符都会折叠,所以一个简单的修复你所做的就是使用 echo "$output"
.
也就是说,我建议不要使用 ls -l
来获取您的文件名及其大小,因为该工具不是为解析而设计的。当您有一个有趣的文件名时,任何基于列的方法都会失败。
使用 GNU stat
允许您获取文件大小并控制输出,使用空字节 [=16=]
使名称可以安全解析:
stat --printf '%s[=10=]%n[=10=]' * | awk -v RS='[=10=]' '
NR % 2 { total += [=10=]; next } # add to total on odd lines, skip to next line
{ files[++n] = [=10=] } # 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 += ; files[NR] = substr([=11=], length() + 2) }
END { print total, "bytes, files:"; for (i = 1; i <= NR; ++i) print files[i] }'
第一个字段包含名称,该行的其余部分是文件名,因此 substr
用于获取该部分。
作为参数传递给 stat
的 *
由 shell 扩展为当前目录中文件的完整列表。您可以通过传递 /path/to/dir/*
或首先 cd
ing 到目标来获取另一个目录中的文件。您也可以使用循环,例如:
for dir in dir1 dir2 dir3; do
( cd "$dir" && stat -c '%s %n' * | awk '...')
done
这里我使用了一个 ( subshell )
作为在每次循环迭代后返回到原始目录的惰性方式。
为了保持变量的结构,应该用双引号引起来。
示例:
多行变量:
x='hey
> there'
不加引号:
echo $x
hey there
双引号:
echo "$x"
hey
there
我正在尝试执行以下操作:
文件夹 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 += } END{print total}'`
这个简单的给出:800
现在我想开始构建输出字符串,所以我试图获取文件名列表(我认为是 $9 列),我是这样尝试的:
output=`ls -l /some/folder/ | awk 'START {total = 0; files=""}; {total += files="\n" files } END{print total "files:" files}'`
echo $output
给出以下内容:
800 filename1 filename2 filename3
我想让它显示:
800
filename1
filename2
filename3
我不明白为什么这些行没有拆分成新行?
ls -l | awk 'NR > 1 {s+=; f=f"\n"$NF} END{print s,f}'
ls -l
输出中的第一行被忽略 (NR > 1
)。 5th
字段(文件大小)中的所有行都加在一个变量s
中。文件名附加到变量 f
(以换行符分隔)。在 END
块中,打印 s
和 f
.
示例:
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+=; f=f"\n"$NF} END{print s,f}'
495
ff
gg
hh
如果您想将其保存到变量中并稍后打印出来:
var=$(ls -l | awk 'NR > 1 {s+=; f=f"\n"$NF} END{print s,f}')
echo "$var"
White space,当你不在 shell 中引用你的变量时,包括换行符都会折叠,所以一个简单的修复你所做的就是使用 echo "$output"
.
也就是说,我建议不要使用 ls -l
来获取您的文件名及其大小,因为该工具不是为解析而设计的。当您有一个有趣的文件名时,任何基于列的方法都会失败。
使用 GNU stat
允许您获取文件大小并控制输出,使用空字节 [=16=]
使名称可以安全解析:
stat --printf '%s[=10=]%n[=10=]' * | awk -v RS='[=10=]' '
NR % 2 { total += [=10=]; next } # add to total on odd lines, skip to next line
{ files[++n] = [=10=] } # 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 += ; files[NR] = substr([=11=], length() + 2) }
END { print total, "bytes, files:"; for (i = 1; i <= NR; ++i) print files[i] }'
第一个字段包含名称,该行的其余部分是文件名,因此 substr
用于获取该部分。
作为参数传递给 stat
的 *
由 shell 扩展为当前目录中文件的完整列表。您可以通过传递 /path/to/dir/*
或首先 cd
ing 到目标来获取另一个目录中的文件。您也可以使用循环,例如:
for dir in dir1 dir2 dir3; do
( cd "$dir" && stat -c '%s %n' * | awk '...')
done
这里我使用了一个 ( subshell )
作为在每次循环迭代后返回到原始目录的惰性方式。
为了保持变量的结构,应该用双引号引起来。
示例:
多行变量:
x='hey
> there'
不加引号:
echo $x
hey there
双引号:
echo "$x"
hey
there