我有一些文本文件,我希望能够将任何文件中的任意一行向上或向下移动一行(文件开头或结尾的行将保持原样)。我有一些工作代码,但它看起来很笨拙,我不相信我已经涵盖了所有边缘情况,所以我想知道是否有一些工具或范式可以更好地做到这一点(例如更容易理解代码(对于其他读者或我在 6 个月内),更容易调试,更容易维护;“更高效”不是很重要)。
move_up() {
# fetch line with head -<line number> | tail -1
# insert that one line higher
# delete the old line
sed -i -e "$((line_number-1))i$(head -$line_number $file | tail -1)" -e "${line_number}d" "$file"
}
move_down() {
file_length=$(wc -l < "$file")
if [[ "$line_number" -ge $((file_length - 1)) ]]; then
# sed can't insert past the end of the file, so append the line
# then delete the old line
echo $(head -$line_number "$file" | tail -1) >> "$file"
sed -i "${line_number}d" "$file"
else
# get the line, and insert it after the next line, and delete the original
sed -i -e "$((line_number+2))i$(head -$line_number $file | tail -1)" -e "${line_number}d" "$file"
fi
}
Run Code Online (Sandbox Code Playgroud)
我可以对这些函数内部或外部的输入进行错误检查,但如果正确处理错误输入(如非整数、不存在的文件或大于文件长度的行号),则会加分。
我希望它在现代 Debian/Ubuntu 系统上的 Bash 脚本中运行。我并不总是具有 root 访问权限,但可以期望安装“标准”工具(例如共享 Web 服务器),并且如果我能证明请求的合理性,我可能能够请求安装其他工具(尽管较少的外部依赖项总是更好) )。
例子:
$ cat b
1
2
3
4
$ file=b line_number=3 move_up
$ cat b
1
3
2
4
$ file=b line_number=3 move_down
$ cat b
1
3
4
2
$
Run Code Online (Sandbox Code Playgroud)
don*_*sti 13
与Archemar的建议类似,您可以使用以下脚本编写ed
:
printf %s\\n ${linenr}m${addr} w q | ed -s infile
Run Code Online (Sandbox Code Playgroud)
IE
linenr # is the line number
m # command that moves the line
addr=$(( linenr + 1 )) # if you move the line down
addr=$(( linenr - 2 )) # if you move the line up
w # write changes to file
q # quit editor
Run Code Online (Sandbox Code Playgroud)
例如移动行号。21
一排:
printf %s\\n 21m19 w q | ed -s infile
Run Code Online (Sandbox Code Playgroud)
移动行号 21
下一行:
printf %s\\n 21m22 w q | ed -s infile
Run Code Online (Sandbox Code Playgroud)
但是由于您只需要将某一行向上或向下移动一行,您也可以说您实际上想要交换两个连续的行。见面sed
:
sed -i -n 'addr{h;n;G};p' infile
Run Code Online (Sandbox Code Playgroud)
IE
addr=${linenr} # if you move the line down
addr=$(( linenr - 1 )) # if you move the line up
h # replace content of the hold buffer with a copy of the pattern space
n # read a new line replacing the current line in the pattern space
G # append the content of the hold buffer to the pattern space
p # print the entire pattern space
Run Code Online (Sandbox Code Playgroud)
例如移动行号。21
一排:
sed -i -n '20{h;n;G};p' infile
Run Code Online (Sandbox Code Playgroud)
移动行号 21
下一行:
sed -i -n '21{h;n;G};p' infile
Run Code Online (Sandbox Code Playgroud)
我使用了gnu sed
上面的语法。如果便携性是一个问题:
sed -n 'addr{
h
n
G
}
p' infile
Run Code Online (Sandbox Code Playgroud)
除此之外,通常的检查:文件存在且可写;file_length > 2
; line_no. > 1
; line_no. < file_length
;