Reputation: 7186
I have a file with options for a command I run. Whenever I run the command I want it to run with the options defined in the first line which is not commented out. I do this using this bash script:
while read run opt c; do
[[ $run == \#* ]] && continue
./submit.py $opt $run -c "$c"
break
done < to_submit.txt
The file to_submit.txt has entries like this:
#167993 options/optionfile.py long description
167995 options/other_optionfile.py other long description
...
After having run the submit script with the options in the last not commented out line, I want to comment out that line after the command ran successfully.
I can find the line number of the options I used adding this to the while loop:
line=$(grep -n "$run" to_submit.txt | grep "$opt" | grep "$c" | cut -f 1 -d ":")
But I'm not sure how to actually prepend a # to that line now. I could probably use head and tail to save the other lines and process that line separately and combine it all back into the file. But this sounds like it's to complicated, there must be an easier sed or awk solution to this.
Upvotes: 1
Views: 181
Reputation: 7186
After some searching around I found that
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
seems to solve this (without needing to find the line number first, just comparing $ run and $opt). This assumes that the combination of run and opt is enough to identify a line and the comment is not needed (which happens to be true in my case). Not sure how the comment which is spanning multiple fields in awk would also be taken into account.
Upvotes: -1
Reputation: 437833
Using GNU sed
is probably simplest here:
sed '0,/^[^#]/ s//#&/' file
Add option -i
if you want to update file
in place.
'0,/^[^#]/
matches all lines up to and including the first one that doesn't start with #
s//#&/
then prepends #
to that line.
s//.../
(i.e., an empty regex) reuses the last matching regex in the range, which is /^[^#]/
in this case.Note that the command doesn't work with BSD/OSX sed
, unfortunately, because starting a range with 0
so as to allow the range endpoint to match the very first line also is not supported there. It is possible to make the command work with BSD/OSX sed
, but it's more cumbersome.
Upvotes: 2
Reputation: 8084
If the input/output file is not very large, you can do it all in Bash:
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"
The lines of the file are put in the outputlines
array, with a hash prepended to the line that was used in the ./submit.py
command. If the command runs successfully, the file is overwritten with the lines in outputlines
.
Upvotes: 0
Reputation: 203532
$ awk '!f && sub(/^[^#]/,"#&"){f=1} 1' file
#167993 options/optionfile.py long description
#167995 options/other_optionfile.py other long description
...
To overwrite the contents of the original file:
awk '!f && sub(/^[^#]/,"#&"){f=1} 1' file > tmp && mv tmp file
just like with any other UNIX command.
Upvotes: 4