Gra*_*ham 6 awk image-processing ascii-art
所以...我知道我可以使用tac或其他一些工具来反转文件中的行顺序,但是如何在其他维度中重新排序,即水平?我正在尝试使用以下awk脚本:
{
out="";
for(i=length($0);i>0;i--) {
out=out substr($0,i,1)}
print out;
}
Run Code Online (Sandbox Code Playgroud)
这似乎扭转了角色,但它是乱码,我不明白为什么.我错过了什么?
我在awk中这样做,但还有更好的东西吗? sed, 也许?
这是一个例子.输入数据如下所示:
$ cowsay <<<"hello"
_______
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Run Code Online (Sandbox Code Playgroud)
输出看起来像这样:
$ cowsay <<<"hello" | rev
_______
> olleh <
-------
^__^ \
_______\)oo( \
\/\) \)__(
| w----||
|| ||
Run Code Online (Sandbox Code Playgroud)
请注意,无论是使用rev还是我自己的awk脚本,输出都是相同的.正如你所看到的,事情是相反的,但......它被破坏了.
rev很好,但它不填充输入行.它只是逆转了它们.
你看到的"破坏"是因为一行可能是20个字符长,而下一行可能是15个字符长.在输入文本中,它们共享一个左侧列.但是在输出文本中,他们需要共享一个右侧列.
所以你需要填充.哦,和不对称的逆转,正如约阿希姆所说.
这是我的revawk:
#!/usr/bin/awk -f
#
length($0)>max {
max=length($0);
}
{
# Reverse the line...
for(i=length($0);i>0;i--) {
o[NR]=o[NR] substr($0,i,1);
}
}
END {
for(i=1;i<=NR;i++) {
# prepend the output with sufficient padding
fmt=sprintf("%%%ds%%s\n",max-length(o[i]));
printf(fmt,"",o[i]);
}
}
Run Code Online (Sandbox Code Playgroud)
(我这样做了gawk;我认为我没有使用任何gawkisms,但如果你使用更经典的awk变体,你可能需要调整它.)
使用方法与使用rev的方式相同.
ghoti@pc:~$ echo hello | cowsay | ./revawk | tr '[[]()<>/\\]' '[][)(><\\/]'
_______
< olleh >
-------
^__^ /
_______/(oo) /
/\/( /(__)
| w----||
|| ||
Run Code Online (Sandbox Code Playgroud)
如果您愿意这样做,您甚至可以通过将其添加到最后printf一行来从awk脚本中运行翻译:
printf(fmt," ",o[i]) | "tr '[[]()<>/\\]' '[][)(><\\/]'";
Run Code Online (Sandbox Code Playgroud)
但我不推荐它,因为它使revawk命令对其他应用程序不那么有用.
你的线条长度不一样,所以反转奶牛会折断它。您需要做的是将线条“填充”为相同长度,然后反转。
例如;
cowsay <<<"hello" | awk '{printf "%-40s\n", $0}' | rev
Run Code Online (Sandbox Code Playgroud)
将它填充到 40 列,然后反转。
编辑:@ghti 做了一个脚本,肯定能打败这个简单的反向,看看他的回答。
这是使用GNU awk和的一种方式rev
运行如下:
awk -f ./script.awk <(echo "hello" | cowsay){,} | rev
Run Code Online (Sandbox Code Playgroud)
内容script.awk:
FNR==NR {
if (length > max) {
max = length
}
next
}
{
while (length < max) {
$0=$0 OFS
}
}1
Run Code Online (Sandbox Code Playgroud)
或者,这是单行:
awk 'FNR==NR { if (length > max) max = length; next } { while (length < max) $0=$0 OFS }1' <(echo "hello" | cowsay){,} | rev
Run Code Online (Sandbox Code Playgroud)
结果:
_______
> olleh <
-------
^__^ \
_______\)oo( \
\/\) \)__(
| w----||
|| ||
Run Code Online (Sandbox Code Playgroud)
这是另一种使用方式GNU awk:
运行如下:
awk -f ./script.awk <(echo "hello" | cowsay){,}
Run Code Online (Sandbox Code Playgroud)
内容script.awk:
BEGIN {
FS=""
}
FNR==NR {
if (length > max) {
max = length
}
next
}
{
while (length < max) {
$0=$0 OFS
}
for (i=NF; i>=1; i--) {
printf (i!=1) ? $i : $i ORS
}
}
Run Code Online (Sandbox Code Playgroud)
或者,这是单行:
awk 'BEGIN { FS="" } FNR==NR { if (length > max) max = length; next } { while (length < max) $0=$0 OFS; for (i=NF; i>=1; i--) printf (i!=1) ? $i : $i ORS }' <(echo "hello" | cowsay){,}
Run Code Online (Sandbox Code Playgroud)
结果:
_______
> olleh <
-------
^__^ \
_______\)oo( \
\/\) \)__(
| w----||
|| ||
Run Code Online (Sandbox Code Playgroud)
说明:
这是对第二个答案的解释.我假设基本知识awk:
FS="" # set the file separator to read only a single character
# at a time.
FNR==NR { ... } # this returns true for only the first file in the argument
# list. Here, if the length of the line is greater than the
# variable 'max', then set 'max' to the length of the line.
# 'next' simply means consume the next line of input
while ... # So when we read the file for the second time, we loop
# through this file, adding OFS (output FS; which is simply
# a single space) to the end of each line until 'max' is
# reached. This pad's the file nicely.
for ... # then loop through the characters on each line in reverse.
# The printf statement is short for ... if the character is
# not at the first one, print it; else, print it and ORS.
# ORS is the output record separator and is a newline.
Run Code Online (Sandbox Code Playgroud)
您可能需要了解的其他一些事项:
该{,}通配符后缀是用于重复输入的文件名两次的简写.不幸的是,它不是标准的Bourne shell.但是,您可以改为使用:
<(echo "hello" | cowsay) <(echo "hello" | cowsay)
Run Code Online (Sandbox Code Playgroud)
此外,在第一个例子中,{ ... }1是简称{ ... print $0 }
HTH.