我正在尝试编写自己的脚本来改进一些自动格式化,然后再提交到远程存储库。我在 IDE 中使用缩进指南,并且适用于我的语言 (FORTRAN) 的自动格式化程序不支持缩进空行。我本质上想用来sed
遍历文件的行,如果该行为空,则向该行添加空格,直到它与该行具有相同数量的空格它上面(因此忽略第一行)。因为我想将其用作预提交挂钩的一部分,所以如果文件通过了要求并且没有被修改,那就太棒了。
未格式化文件的示例,其中>
对应于空格:
Start of document - First line is ignored
Second line has text and is therefore ignored
>>>>Third line has four spaces so below (empty line) should have 4 spaces added.
>>>>>>>>Third line has 8 spaces so below (empty line) should have 8 spaces added.
End of document
期望的输出:
Start of document - First line is ignored
Second line has text and is therefore ignored
>>>>Third line has four spaces so below (empty line) should have 4 spaces added.
>>>>
>>>>>>>>Third line has 8 spaces so below (empty line) should have 8 spaces added.
>>>>>>>>
End of document
另外,与此相关的是我想缩进以感叹号开头的行在第 1 栏(前面没有任何空格)到上面一行的级别(因为我使用的自动格式化程序不支持这一点)。
未格式化文件的示例,其中>
对应于空格:
Start of document - First line is ignored
! Second line starts with exclamation mark in column 1 so it is indented to level of above line
>>>>Third line has 4 spaces to start
!This should have 4 spaces added to it because the first character is ‘!’ and above line has 4
>>>>>>>>This line has 8 spaces
>>>>>>>>!This line shouldn’t be changed as it begins with a space, not an exclamation mark.
End of document
期望的输出:
Start of document - First line is ignored
! Second line starts with exclamation mark in column 1 so it is indented to level of above line
>>>>Third line has 4 spaces to start
>>>>!This should have 4 spaces added to it because the first character is ‘!’ and above line has 4
>>>>>>>>This line has 8 spaces
>>>>>>>>!This line shouldn’t be changed as it begins with a space, not an exclamation mark.
End of document
我对 bash 脚本非常陌生,因此任何解决方案如何工作的解释都会很棒,并提前感谢您的帮助!
编辑:按照评论的要求用文本替换图像!
答案1
使用sed
:
sed -n \
-e '/^!/ { G; s/\(.*\)\n\(.*\)/\2\1/; }' \
-e '/^$/g' \
-e p \
-e 's/^\( *\).*/\1/' \
-e h file
这使用一系列sed
编辑表达式来执行所需的缩进。该脚本使用保留空间( 中的辅助不可编辑缓冲区sed
)将当前缩进保存为多个空格字符。
!
如果该行的第一个位置以 a 开头,则触发第一个表达式。该表达式将保留空间中的任何内容附加到当前行末尾,并以换行符作为分隔符,然后交换缓冲区的两部分,同时删除换行符。这会将!
-line 缩进到当前的缩进级别。
第二个表达式针对空行而触发,并用保留空间中的任何内容替换空行。这负责向空行添加适当数量的空格。
第三个表达式输出编辑缓冲区的当前内容。我们明确地执行此操作,因为它当前已正确缩进(由于是 -line !
、空行,或者是我们尚未修改的其他行),并且我们很快需要修改它以便能够处理文档的其余部分正确。
最后两个操作在空格缩进结束处截断当前行,然后将剩余的缩进保存到保留空间以供下一次循环使用。将最后一个替换中的空格替换为例如,[[:blank:]]
以匹配使用制表符或空格进行的任何缩进。
答案2
像这样的任务最好用awk
or之类的语言来完成perl
(因为 sed 没有变量)。
以下 Perl 一行代码适用于您的两种要求。我已将输出通过管道传输到,cat -A
以便您可以看到空格已添加到需要的行的开头 -$
表示每行的结尾。
第一个语句将变量的内容添加$spaces
到行 ( $_
) 的开头,如果它为空或!
在第一个输入行上以 - 开头,$spaces
则将为空。第二条语句将当前行开头的空格(如果有)捕获到 中$spaces
,准备在下一个输入行中使用。
注意:这里使用\h
,表示水平空白(ASCII 文件中的空格和制表符,以及一些 unicode 空格字符)。如果您希望它仅使用空格字符,请将 更改\h
为单个空格:($spaces) = (/^( *)/)
。
第一个输入文件:
$ perl -p -e 'if (/^($|!)/) { $_ = $spaces . $_ };
($spaces) = (/^(\h*)/)' input1.txt | cat -A
Start of document - First line is ignored$
Second line has text and is therefore ignored$
Third line has four spaces so below (empty line) should have 4 spaces added.$
$
Third line has 8 spaces so below (empty line) should have 8 spaces added.$
$
End of document$
第二个文件:
$ perl -p -e 'if (/^($|!)/) { $_ = $spaces . $_ };
($spaces) = (/^(\h*)/)' input2.txt | cat -A
Start of document - First line is ignored$
! Second line starts with exclamation mark in column 1 so it is indented to level of above line$
Third line has 4 spaces to start$
!This should have 4 spaces added to it because the first character is '!' and above line has 4$
This line has 8 spaces$
!This line shouldn't be changed as it begins with a space, not an exclamation mark.$
End of document$
另请注意:这会将文件(无论是否修改)打印到标准输出。如果您希望它修改原始文件,请将 perl 的-i
选项添加到命令行 - 这与sed
的-i
选项类似。请参阅man perlrun
并搜索-i\[extension\]
详细信息) - 特别要注意以下几点:
请注意,由于
-i
在创建同名新文件之前重命名或删除了原始文件,因此不会保留 Unix 风格的软链接和硬链接。
git
似乎并不关心文件的索引节点号是否发生变化,仅当内容发生变化时...但是如果您需要保留硬链接或者只是不想覆盖输入文件(如果它尚未更改),那么重定向到临时文件,并且仅当diff
或cmp
指示临时文件不同时才覆盖。