如何将文本文件中的一行向上或向下移动一行?

如何将文本文件中的一行向上或向下移动一行?

我有一些文本文件,我希望能够移动任何文件中上一行或下一行的任意行(文件开头或结尾的行将保留在原来的位置)。我有一些工作代码,但看起来很混乱,而且我不相信我已经涵盖了所有边缘情况,所以我想知道是否有一些工具或范例可以更好地做到这一点(例如更容易理解代码(对于其他读者或我在 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
}

我可以对这些函数内部或外部的输入进行错误检查,但如果正确处理错误的输入(例如非整数、不存在的文件或大于文件长度的行号),则会加分。

我希望它在现代 Debian/Ubuntu 系统上的 Bash 脚本中运行。我并不总是具有 root 访问权限,但可以期望安装“标准”工具(想想共享网络服务器),并且可能如果我可以证明请求的合理性,就能够请求安装其他工具(尽管外部依赖项越少越好)。

例子:

$ 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
$ 

答案1

如同阿彻马尔的建议,您可以使用以下脚本编写此脚本ed

printf %s\\n ${linenr}m${addr} w q | ed -s infile

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

例如移动行号。21一队:

printf %s\\n 21m19 w q | ed -s infile

移动行号21向下一行:

printf %s\\n 21m22 w q | ed -s infile

但由于您只需将某一行向上或向下移动一行,您也可以说您实际上想要交换两个连续的行。见面sed

sed -i -n 'addr{h;n;G};p' infile

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

例如移动行号。21一队:

sed -i -n '20{h;n;G};p' infile

移动行号21向下一行:

sed -i -n '21{h;n;G};p' infile

我使用了gnu sed上面的语法。如果可移植性是一个问题:

sed -n 'addr{
h
n
G
}
p' infile

除此之外,通常的检查:文件存在并且可写;file_length > 2; line_no. > 1; line_no. < file_length;

答案2

vi 有一个命令叫 movem

您可以在文本模式下使用 vi : ex

  $line_number=7
  $line_up=$(($line_number + 1 ))
  (echo ${line_number}m${line_up} ; echo wq ) | ex foo

在哪里

  • foo是你的文件

答案3

使用 vims(在 sed 模式下使用 vim):https://github.com/MilesCranmer/vim-stream

你可以:

cat file.txt | vims "$NUMBERm.-1"

将该行向下移动一位。

相关内容