gna*_*ian 124 sorting bash awk text
我有一个看起来像这样的CSV文件
AS2345,ASDF1232, Mr. Plain Example, 110 Binary ave.,Atlantis,RI,12345,(999)123-5555,1.56 AS2345,ASDF1232, Mrs. Plain Example, 1121110 Ternary st. 110 Binary ave..,Atlantis,RI,12345,(999)123-5555,1.56 AS2345,ASDF1232, Mr. Plain Example, 110 Binary ave.,Liberty City,RI,12345,(999)123-5555,1.56 AS2345,ASDF1232, Mr. Plain Example, 110 Ternary ave.,Some City,RI,12345,(999)123-5555,1.56
我需要按行长度排序,包括空格.以下命令不包含空格,有没有办法修改它以便它对我有用?
cat $@ | awk '{ print length, $0 }' | sort -n | awk '{$1=""; print $0}'
Run Code Online (Sandbox Code Playgroud)
nei*_*llb 200
cat testfile | awk '{ print length, $0 }' | sort -n -s | cut -d" " -f2-
Run Code Online (Sandbox Code Playgroud)
或者,对任何等长线进行原始(可能是无意的)子排序:
cat testfile | awk '{ print length, $0 }' | sort -n | cut -d" " -f2-
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,我们都通过远离awk来解决你所说的问题.
该问题没有说明是否需要对匹配长度的行进行进一步排序.我假设这是不需要的,并建议使用-s
(--stable
)来防止这些行相互排序,并保持它们在输入中出现的相对顺序.
(那些想要更多控制排序这些关系的人可能会考虑排序的--key
选择.)
值得注意的是:
echo "hello awk world" | awk '{print}'
echo "hello awk world" | awk '{$1="hello"; print}'
Run Code Online (Sandbox Code Playgroud)
他们分别屈服
hello awk world
hello awk world
Run Code Online (Sandbox Code Playgroud)
(gawk's)手册的相关部分仅提到当你改变一个字段时,awk将重建整个$ 0(基于分隔符等).我想这不是疯狂的行为.它有这个:
"最后,有时候使用字段和OFS的当前值强制awk重建整个记录很方便.为此,使用看似无害的任务:"
$1 = $1 # force record to be reconstituted
print $0 # or whatever else with $0
Run Code Online (Sandbox Code Playgroud)
"这迫使重建记录."
aa A line with MORE spaces
bb The very longest line in the file
ccb
9 dd equal len. Orig pos = 1
500 dd equal len. Orig pos = 2
ccz
cca
ee A line with some spaces
1 dd equal len. Orig pos = 3
ff
5 dd equal len. Orig pos = 4
g
Run Code Online (Sandbox Code Playgroud)
Cal*_*leb 22
来自neillb的AWK解决方案非常棒,如果您真的想要使用awk
它,它解释了为什么它在那里很麻烦,但如果您想要的是快速完成工作并且不关心您在做什么,一个解决方案是使用Perl的sort()
函数使用自定义caparison例程迭代输入行.这是一个班轮:
perl -e 'print sort { length($a) <=> length($b) } <>'
Run Code Online (Sandbox Code Playgroud)
您可以将它放在您需要它的管道中,或者接收STDIN(来自cat
或重定向)或者只是将文件名作为另一个参数提供给perl并让它打开文件.
就我而言,我需要最长行第一,所以我换出$a
,并$b
在比较.
anu*_*ava 14
请尝试此命令:
awk '{print length, $0}' your-file | sort -n | cut -d " " -f2-
Run Code Online (Sandbox Code Playgroud)
这是一个具有相同功能的 Python 单行代码,已使用 Python 3.9.10 和 2.7.18 进行了测试。它比 Caleb 的 perl 解决方案快约 60%,并且输出相同(使用包含 1480 万行的 300MiB 单词列表文件进行测试)。
python -c 'import sys; sys.stdout.writelines(sorted(sys.stdin.readlines(), key=len))'
Run Code Online (Sandbox Code Playgroud)
基准:
python -c 'import sys; sys.stdout.writelines(sorted(sys.stdin.readlines(), key=len))'
real 0m5.308s
user 0m3.733s
sys 0m1.490s
perl -e 'print sort { length($a) <=> length($b) } <>'
real 0m8.840s
user 0m7.117s
sys 0m2.279s
Run Code Online (Sandbox Code Playgroud)
基准测试结果
以下是基准测试的结果.
另外,我添加了另一个Perl解决方案:
perl
实验使用:
结果:
该length()
函数确实包含空格。我只会对您的管道进行细微调整(包括避免UUOC)。
awk '{ printf "%d:%s\n", length($0), $0;}' "$@" | sort -n | sed 's/^[0-9]*://'
Run Code Online (Sandbox Code Playgroud)
该sed
命令直接删除命令添加的数字和冒号awk
。或者,保留格式awk
:
awk '{ print length($0), $0;}' "$@" | sort -n | sed 's/^[0-9]* //'
Run Code Online (Sandbox Code Playgroud)
Pure Bash:
declare -a sorted
while read line; do
if [ -z "${sorted[${#line}]}" ] ; then # does line length already exist?
sorted[${#line}]="$line" # element for new length
else
sorted[${#line}]="${sorted[${#line}]}\n$line" # append to lines with equal length
fi
done < data.csv
for key in ${!sorted[*]}; do # iterate over existing indices
echo -e "${sorted[$key]}" # echo lines with equal length
done
Run Code Online (Sandbox Code Playgroud)