我有一个文件,其中包含我运行的命令的选项。每当我运行命令时,我希望它使用第一行中定义的选项运行,该选项未注释掉。我使用这个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解决方案。
答案 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中多个字段的评论。