1

I have a shell script that looks like the following:

#!/bin/bash
for file in $1/*.html; do
   echo "Working on $file ..."

   # delete headers in html files.
   sed -n '1,9d' $file

   # delete the last 4 lines of the file.
   sed -n -e :a -e '1,4!{P;N;D;};N;ba'

   # ant runs regex task on all apt files
   ant -Dtarget.file=$file

   # all .html are changed to .md
   mv $file `echo $file | sed 's/\(.*\.\)html/\1md/'` ;

done

but the script hangs on the first sed command and I have to force exit. I'm wondering if there's anything wrong about the way I've set this up?

If I remove the first two sed commands, I can run the other parts of the script, including that final one with a sed command in it.

1
  • 1
    The mv makes me cringe due to the useless and expensive fork to yet another sed. If you just want to replace an extension in a filename stored in a variable, use mv $file ${file%.html}.md. Commented May 12, 2012 at 16:55

3 Answers 3

4

I think you'll find it's hanging on the second sed, where you don't provide a file name to work on. In other words, it will take its standard input from the terminal.

You won't get output from the first sed since -n prevents the default printing of the pattern space. If you're trying to change the actual file rather than output the changes to standard output, you need the -i inplace editor.

If you can't use the inplace option, you'll have to do something like:

sed -n '1,9d' ${file} >${file}.tmp0
sed -n -e :a -e '1,4!{P;N;D;};N;ba' ${file}.tmp0 >${file}
rm -f ${file}.tmp0

This uses a temporary file for making the changes except for the last change, which overwrites the original file. Keep in mind that this changes the original - if that's not what you want, you can change the second sed to output to ${file}.tmp2 but you'll have to adjust your subsequent commands to take that into account.

If you really want to delete the first nine and last four lines of a file, you can also use something like:

head --lines=-4 oldfile.txt | tail --lines=+10 >newfile.txt

provided you have a [rd]ecent implementation of head/tail. The head prints all but the last four lines and the tail starts printing at line ten.

Sign up to request clarification or add additional context in comments.

2 Comments

You are right, it didn't hang when I added the filename. However, still no lines were deleted from the head or tail of the files. I unfortunately do not have a decent head ... I mean the shell command :) ... but I managed to use tail for getting rid of the headers and ant-based regex for snipping the lines at the end.
@user766353, no lines were deleted since you're not replacing the file with the output of sed. sed normally writes the changes to standard output (rather than changing the original file). What you'd normally see on the output is those changes but, since you've used -n to suppress the default pattern space output, they won't appear. See my update for a solution (making sure the file itself is updated).
0

What command are you running? If nothing matches the file glob, then it will physically insert the unexpanded string there.

For example, try this:

$ for i in foo/*.bar; do echo $i; done
foo/*.bar

So your sed script is bombing out because the file name it is receiving doesn't exist, which means it will act as if no file argument was specified (ie stdin).

1 Comment

If the file doesn't exist, I'm pretty certain sed doesn't act as if you specified no file, instead it complains bitterly :-)
0

Change the first line to:

#!/bin/bash -x

This will show you each command as bash executes it, after all expansions have taken place.

My guess is that $1/*.html isn't matching any files; hence the sed line evaluates to just sed -n '1,9d' and so sed is trying to read from stdin

2 Comments

No, actually it will expand the $1 okay (to possibly an empty string) and leave the * untouched, in which case you'll get an error, unless you actually have a literal *.html file which is both unlikely and unwise :-)
But as @paxdiablo also said, the actual root problem here is almost certainly that it's hanging on the second sed. Using bash -x is a handy troubleshooting technique though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.