2

I have the following bash file called "file" (the real one does something useful):

ed db/seeds.rb <<EOF
1,$-1d
a
123
456
.
w
q
EOF

When I run "bash file" it doesn't delete any lines. If I use 1d instead of 1,$-1d it does delete the first line.

Why doesn't this work? I could easily do a workaround, but I'm curious why this doesn't work.

6
  • ed is meant to be run interactively. Unless you're using expect or similar, the interactive portions can't be scripted in shell script.
    – ernie
    Aug 20, 2014 at 17:06
  • When you have a portion of a script looking like: ed file <<EOF The script runs the command ("ed" in this case) such that the command thinks the following lines are inputed interactively. This continues until it encounters a line contained only the text following the << (EOF in this case). I use this feature all the time. Aug 20, 2014 at 17:38
  • tail is a dedicated tool for this task.
    – gronostaj
    Aug 20, 2014 at 17:46
  • Again, this is just a simple example of what I'm doing in my real application. Tail would work, but it's not what my question is about. It's about ed. Aug 20, 2014 at 17:48
  • By the way, @ernie, diff -e produces an ed script to convert file1 to file2. ed has supported non-interactive use since day 1, in the 1970s. Aug 20, 2014 at 21:28

2 Answers 2

1

The problem is that the shell is interpreting the $ in the 1,$-1d command.  (Specifically, in my tests, it interprets $- as the collection of set flags.)  The best way to fix this is to quote or escape the EOF string, as in

ed db/seeds.rb <<\EOF

or

ed db/seeds.rb <<"EOF"

Alternatively, you could escape (i.e., put a backslash in front of) every $ in your “here document”.

3
  • I ran into the same problem just now and it was in a context that was easier to understand. I had used solution of escaping the $ before (but obviously didn't remember), but I never knew the alternatives that you suggested. Less painful alternatives. Thanks. Aug 21, 2014 at 0:50
  • Barmar makes a good point in his comment: if you want to, you can use shell variables in your “here document”. In that case, you should not quote or escape the EOF string, but just escape the $s that you want handled literally (leaving the variable references, e.g., $HOME, alone). Aug 21, 2014 at 15:52
  • Thanks for the reminder. I don't use shell variables very often. The dollar signs typically appear nowadays in angularjs code. Aug 22, 2014 at 15:47
1

sed is simpler in this case. Pick one of:

sed -i -n '$p' file
sed -i '$!d' file

The error with your code is that the shell is expanding $- before passing the script to ed. This will work:

# quoting the heredoc word:
ed db/seeds.rb <<'EOF'
1,$-1d
w
q
EOF
4
  • Unfortunately, in my real use, I add lines of text after I deleted what was there already. Aug 20, 2014 at 17:46
  • @FredFinkle then append to the file.
    – gronostaj
    Aug 20, 2014 at 17:47
  • If the real application needs to refer to variables in the here-doc, you could use <<EOF and escape the literal dollar signs with backslash.
    – Barmar
    Aug 20, 2014 at 20:52
  • sed doesn't edit in place, so it's a different beast. Aug 8, 2022 at 22:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .