将#添加到尚未拥有#的第一行#

时间:2016-02-23 10:42:54

标签: awk sed

我有一个文件,其中包含我运行的命令的选项。每当我运行命令时,我希望它使用第一行中定义的选项运行,该选项未注释掉。我使用这个bash脚本执行此操作:

while read run opt c; do
  [[ $run == \#* ]] && continue
  ./submit.py $opt $run -c "$c"
  break
done < to_submit.txt

文件to_submit.txt包含以下条目:

#167993 options/optionfile.py long description
167995 options/other_optionfile.py other long description
...

在运行提交脚本并使用最后一个未注释掉的行中的选项后,我想在命令成功运行后注释掉该行。

我可以找到我使用的选项的行号,将其添加到while循环中:

line=$(grep -n "$run" to_submit.txt | grep "$opt" | grep "$c" | cut -f 1 -d ":")

但我现在还不确定如何在该行前加上#。我可以使用head和tail来保存其他行并单独处理该行并将它们全部合并到文件中。但这听起来很复杂,必须有一个更简单的sed或awk解决方案。

4 个答案:

答案 0 :(得分:4)

$ awk '!f && sub(/^[^#]/,"#&"){f=1} 1' file
#167993 options/optionfile.py long description
#167995 options/other_optionfile.py other long description
...

覆盖原始文件的内容:

awk '!f && sub(/^[^#]/,"#&"){f=1} 1' file > tmp && mv tmp file

就像使用任何其他UNIX命令一样。

答案 1 :(得分:2)

使用 GNU sed可能最简单:

sed '0,/^[^#]/ s//#&/' file

如果您想更新-i,请添加选项file

  • '0,/^[^#]/匹配所有行,包括第一个不以#
  • 开头的行
  • s//#&/然后将#添加到该行。
    • 请注意,s//.../(即正则表达式)会重复使用范围中的最后一个匹配的正则表达式,在这种情况下为/^[^#]/

请注意,该命令不适用于BSD / OSX sed,因为使用0启动范围以允许范围端点匹配第一行也不支持那里。 可以使命令与BSD / OSX sed一起使用,但它更麻烦。

答案 2 :(得分:0)

如果输入/输出文件不是很大,您可以在Bash中完成所有操作:

display:table-cell

文件的行放在optsfile=to_submit.txt has_run_cmd=0 outputlines=() while IFS= read -r inputline || [[ -n $inputline ]] ; do read run opt c <<<"$inputline" if (( has_run_cmd )) || [[ $run == \#* ]] ; then outputlines+=( "$inputline" ) elif ./submit.py "$opt" "$run" -c "$c" ; then has_run_cmd=1 outputlines+=( "#$inputline" ) else exit $? fi done < "$optsfile" (( has_run_cmd )) && printf '%s\n' "${outputlines[@]}" > "$optsfile" 数组中,并在outputlines命令中使用的行前面加上一个哈希值。如果命令成功运行,则文件将被./submit.py中的行覆盖。

答案 3 :(得分:-1)

经过一番搜索,我发现了

awk -v run="$run" -v opt="$opt" '{if($1 == run && $2 == opt) {print "#" $0} else print}' to_submit.txt > temp
mv -b -f temp to_submit.txt

似乎解决了这个问题(无需首先找到行号,只需比较$ run和$ opt)。这假设run和opt的组合足以识别一行并且不需要注释(在我的情况下恰好是这样)。不确定如何考虑跨越awk中多个字段的评论。