在前 X 行之后对文件进行排序的更优雅的方法?
More elegant method of sorting a file after the first X lines?
今天我在 Stack Overflow 上搜索了很多解决方案,发现了很多关于跳过 X 行后排序的问题,但没有真正可靠的通用答案,所以我拼凑了自己的草率方法这样做:
head -n 15 FILE.EXT > temp.txt
tail -n+16 FILE.EXT | sort >> temp.txt
mv temp.txt FILE.EXT
这将对文件进行排序(选择排序选项),同时保留文件前 15 行的顺序。这显然相当不雅,要输入三个文件引用和两个不同的值。理想情况下,如果可能的话,我想提出一个不那么麻烦的命令,因为这似乎是一个非常普遍的愿望,但没有太多支持。
- 有没有人有比我更简单的解决方案?
- 我做的有什么问题吗?潜在问题?
- 这个问题更适合使用脚本,但我的命令可能仍然比一次性创建和执行脚本稍微快一些。
我什至不接近 bash 专家,所以我希望有一些 bash-fu 可以使它成为一个快速的单行。有没有办法在单个命令中创建和引用变量,以便用户只需要输入名称和行号之类的东西?
怎么样:
{ head -n 15 file; tail -n+16 file | sort ; }
此 'one-liner' 生成输出:
awk 'NR <= 15 { print; next } { print | "sort" }'
彻底覆盖原始文件比较困难,通常涉及写入临时文件并在完成后重命名的内容。
作为sputnick ,如果你有GNU awk
,你可以使用-i
选项就地覆盖:
gawk -i 'NR <= 15 { print; next } { print | "sort" }' FILE.EXT
(并且 gawk
通常也安装为 awk
。)
如果您没有 GNU awk
,那么我有一个脚本 ow
派生自 Kernighan & Pike The UNIX Programming Environment 的脚本 overwrite
,它就是这样做的.
用法:
ow FILE.EXT awk 'NR <= 15 { print; next } { print | "sort" }' FILE.EXT
代码:
: "@(#)$Id: ow.sh,v 1.6 2005/06/30 18:14:08 jleffler Exp $"
#
# Overwrite file
# From: The UNIX Programming Environment by Kernighan and Pike
# Amended: remove PATH setting; handle file names with blanks.
case $# in
0|1)
echo "Usage: [=13=] file command [arguments]" 1>&2
exit 1;;
esac
file=""
shift
new=${TMPDIR:-/tmp}/ovrwr.$$.1
old=${TMPDIR:-/tmp}/ovrwr.$$.2
trap "rm -f '$new' '$old' ; exit 1" 0 1 2 15
if "$@" >"$new"
then
cp "$file" "$old"
trap "" 1 2 15
cp "$new" "$file"
rm -f "$new" "$old"
trap 0
exit 0
else
echo "[=13=]: failed - $file unchanged" 1>&2
rm -f "$new" "$old"
trap 0
exit 1
fi
这是旧代码;我已经将近十年没有修改它了,但我已经使用了很多。作为 by Charles Duffy,如果您可能会遇到以破折号开头的文件名(因为这些可能会被误认为 cp
或 mv
的命令行选项),它可以进行一些现代化改造,它应该有一个 shebang 行等。
它还显示了陷阱信号(虽然现在,我通常陷阱'0 1 2 3 13 15
',相当于'EXIT HUP INT QUIT PIPE TERM
')和命名临时文件以防止偶然干扰(使用$$
而不是 mktemp
— 就像我说的,这是旧代码)。
你可以像这样在文件的开头做一个跳过一些行的排序:
{ head -n 15 && sort; } < file > tempfile
之所以有效,是因为 head 在 15 行后停止读取,所以 sort 会看到文件的其余部分。
所以解决了完整的原始问题。
{ head -n 15 && sort; } < file > tempfile && mv tempfile file
今天我在 Stack Overflow 上搜索了很多解决方案,发现了很多关于跳过 X 行后排序的问题,但没有真正可靠的通用答案,所以我拼凑了自己的草率方法这样做:
head -n 15 FILE.EXT > temp.txt
tail -n+16 FILE.EXT | sort >> temp.txt
mv temp.txt FILE.EXT
这将对文件进行排序(选择排序选项),同时保留文件前 15 行的顺序。这显然相当不雅,要输入三个文件引用和两个不同的值。理想情况下,如果可能的话,我想提出一个不那么麻烦的命令,因为这似乎是一个非常普遍的愿望,但没有太多支持。
- 有没有人有比我更简单的解决方案?
- 我做的有什么问题吗?潜在问题?
- 这个问题更适合使用脚本,但我的命令可能仍然比一次性创建和执行脚本稍微快一些。
我什至不接近 bash 专家,所以我希望有一些 bash-fu 可以使它成为一个快速的单行。有没有办法在单个命令中创建和引用变量,以便用户只需要输入名称和行号之类的东西?
怎么样:
{ head -n 15 file; tail -n+16 file | sort ; }
此 'one-liner' 生成输出:
awk 'NR <= 15 { print; next } { print | "sort" }'
彻底覆盖原始文件比较困难,通常涉及写入临时文件并在完成后重命名的内容。
作为sputnick awk
,你可以使用-i
选项就地覆盖:
gawk -i 'NR <= 15 { print; next } { print | "sort" }' FILE.EXT
(并且 gawk
通常也安装为 awk
。)
如果您没有 GNU awk
,那么我有一个脚本 ow
派生自 Kernighan & Pike The UNIX Programming Environment 的脚本 overwrite
,它就是这样做的.
用法:
ow FILE.EXT awk 'NR <= 15 { print; next } { print | "sort" }' FILE.EXT
代码:
: "@(#)$Id: ow.sh,v 1.6 2005/06/30 18:14:08 jleffler Exp $"
#
# Overwrite file
# From: The UNIX Programming Environment by Kernighan and Pike
# Amended: remove PATH setting; handle file names with blanks.
case $# in
0|1)
echo "Usage: [=13=] file command [arguments]" 1>&2
exit 1;;
esac
file=""
shift
new=${TMPDIR:-/tmp}/ovrwr.$$.1
old=${TMPDIR:-/tmp}/ovrwr.$$.2
trap "rm -f '$new' '$old' ; exit 1" 0 1 2 15
if "$@" >"$new"
then
cp "$file" "$old"
trap "" 1 2 15
cp "$new" "$file"
rm -f "$new" "$old"
trap 0
exit 0
else
echo "[=13=]: failed - $file unchanged" 1>&2
rm -f "$new" "$old"
trap 0
exit 1
fi
这是旧代码;我已经将近十年没有修改它了,但我已经使用了很多。作为 cp
或 mv
的命令行选项),它可以进行一些现代化改造,它应该有一个 shebang 行等。
它还显示了陷阱信号(虽然现在,我通常陷阱'0 1 2 3 13 15
',相当于'EXIT HUP INT QUIT PIPE TERM
')和命名临时文件以防止偶然干扰(使用$$
而不是 mktemp
— 就像我说的,这是旧代码)。
你可以像这样在文件的开头做一个跳过一些行的排序:
{ head -n 15 && sort; } < file > tempfile
之所以有效,是因为 head 在 15 行后停止读取,所以 sort 会看到文件的其余部分。
所以解决了完整的原始问题。
{ head -n 15 && sort; } < file > tempfile && mv tempfile file