1

I have a bash script which reads a file having multiple line of text and executes a command on those lines. Sometimes the command work, but sometimes it fails. I want to append a pound sign (#) at the start of the lines of text where the command worked successfully and lines where the command failed they should as it is so that they can be retried in next run of the script. Lines which starts from # doesn't get executed.
My current script looks something like this -

COUNT=1 while read -r LINE; do if [[ ($LINE != \#*) && !(-z "${LINE// }") ]] ; then echo "${LINE}" # execute "$LINE" if [ $? -eq 0 ]; then echo OK # Append pound (#) at the start of the line else echo FAIL # Keep the line in the source file fi fi COUNT=$(( $COUNT + 1 )) done < $SRC_FILE 

As you can see the condition is already there, I just need to replace those echo OK and echo FAIL line of code. I tried this answer, but it removes all the lines in the end, I don't want that, I want to keep the failed lines in the file.

I tried using sed, but it appear to do nothing -

sed -n "${COUNT}s/^/#/" $SRC_FILE >> $SRC_FILE 

Is there any way to do that?

PS: I want to make it work on bash and zsh on both Linux and Mac terminal, especially Mac zsh.

Update:
I tried the following command

sed "${COUNT}s/.*/#&/" $SRC_FILE >$SRC_FILE 

It removes all the line from the source file and make it empty, but if I change the output file, it works, although adds the # in the last line only, since it's still reading from the original source file.

2
  • Is overall goal that you want to add a # at the start of non-empty lines that does not already have a # at the start of the line? Commented May 8, 2019 at 15:46
  • @Kusalananda My goal is to add # at the start of lines which succeed in running the command so that I can skip them in the next run. Lines which already have # in start are anyway not processed. Commented May 8, 2019 at 15:51

2 Answers 2

1

You could do:

#! /bin/sh - src_file=/path/to/file { while read <&3 -r line; do case $line in ('#'*) ;; (*) if eval " $line" 3<&- 4>&-; then echo OK line="# $line" else echo FAIL fi esac printf '%s\n' "$line" >&4 done mv -- "$src_file.new" "$src_file" } 3< "$src_file" 4> "$src_file.new" 

Each line of the file will be evaluated as sh code. Replace sh with bash or zsh if those lines use bash-specific or zsh-specific features.

Here, we're generating a file.new file which we rename to file in the end. That's more or less what sed -i (GNU) or sed -i '' (FreeBSD/macOS) do as well. Generally, you can't easily write to a given file at the same as you are reading it.

0

Using sed [command] file > file will, as you have discovered, not do what you want. The redirection wipes out the contents of file and replaces it with the output of sed.

What you need to do is use sed's built-in ability to modify files in-place:

sed --in-place "$COUNTs/^/#/" file 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.