Reputation: 397
Just new to Bash scripting and programming in general. I would like to automate the deletion of the first line of multiple .data files in a directory. My script is as follows:
#!/bin/bash
for f in *.data ;
do tail -n +2 $f | echo "processing $f";
done
I get the echo message but when I cat the file nothing has changed. Any ideas?
Thanks in advance
Upvotes: 10
Views: 14112
Reputation: 123478
I get the echo message but when I cat the file nothing has changed.
Because simply tail
ing wouldn't change the file.
You could use sed
to modify the files in-place with the first line excluded. Saying
sed -i '1d' *.data
would delete the first line from all .data
files.
EDIT: BSD sed
(on OSX) would expect an argument to -i
, so you can either specify an extension to backup older files, or to edit the files in-place, say:
sed -i '' '1d' *.data
Upvotes: 24
Reputation: 46823
ed
is the standard editor:
shopt -s nullglob
for f in *.data; do
echo "Processing file \`$f'"
ed -s -- "$f" < <( printf '%s\n' "1d" "wq" )
done
The shopt -s nullglob
is here just because you should always use this when using globs, especially in a script: it will make globs expand to nothing if there are no matches; you don't want to run commands with uncontrolled arguments.
Next, we loop on all your files, and use ed
with the commands:
1
: go to first lined
: delete that linewq
: write and quitOptions for ed
:
-s
: tells ed
to shut up! we don't want ed
to print its junk on our screen.--
: end of options: this will make your script much more robust, in case a file name starts with a hypen: in this case, the hyphen will confuse ed
trying to process it as an option. With --
, ed
knows that there are no more options after that and will happily process any files, even those starting with a hyphen.Upvotes: 0
Reputation: 249153
I'd do it this way:
#!/usr/bin/env bash
set -eu
for f in *.data; do
echo "processing $f"
tail -n +2 "$f" | sponge "$f"
done
If you don't have sponge
you can get it in the moreutils
package.
The quotes around the filename are important--they will make it work with filenames containing spaces. And the env
thing at the top is so that people can set which Bash interpreter they want to use via their PATH, in case someone has a non-default one. The set -eu
makes Bash exit if an error occurs, which is usually safer.
Upvotes: 0
Reputation: 15310
You are not changing the file itself. By using tail
you simply read the file and print parts of it to stdout
(the terminal), you have to redirect that output to a temporary file and then overwrite the original file with the temporary one.
#!/usr/bin/env bash
for f in *.data; do
tail -n +2 "$f" > "${f}".tmp && mv "${f}".tmp "$f"
echo "Processing $f"
done
Moreover it's not clear what you'd like to achieve with the echo
command. Why do you use a pipe (|
) there?
sed will give you an easier way to achieve this. See devnull's answer.
Upvotes: 4