7

I would like to modify a bunch of text files from the terminal, more precisey:

add the string '50' to the first line of every text file in /mydat/ ?

Alternatively, if you know of a link to a page on the web that lists commands to manipulate text files from the shell...

user2413
  • 14,337

5 Answers5

7

find and sed are your weapons of choice:

find /mydat/ -exec sed '1i 50' {} \;

That will stick 50 followed by a new line on the beginning of the file.

Alternatively if you don't need recursion or complex selectors for find you can drop find completely:

sed '1i 50' *
Oli
  • 293,335
  • thanks. However a little problem remains (see appended questions for an example).

    – user2413 Nov 02 '10 at 19:09
  • Fixed. I've also added a simplified version that should still do what you need. find is more powerful but you might not need it. I'll add that both versions are somewhat more simple than all these convoluted bash loops. – Oli Nov 02 '10 at 19:22
  • One last thing. I have a file timing.txt and i need to replace the first line of that file by the constant string "49". How do you modify your command? – user2413 Nov 02 '10 at 20:07
  • ok found: sed '1d' timing0.txt > timing0.txt – user2413 Nov 02 '10 at 20:29
3

To edit a file, you need an editor. ed and ex are examples of command based editors, which is useful for editing files from a script. Here's an example inserting a line to every file with .txt extension in /mydata, using ed:

#!/bin/bash
for file in /mydata/*.txt; do
    printf '%s\n' 0a 50 . w | ed -s "$file"
done

That'll handle all kinds of odd characters in the filenames too, unlike all the examples using for-loops with ls in the answers given so far.

Here's a link describing how to use ed: http://bash-hackers.org/wiki/doku.php?id=howto:edit-ed

For getting to grips with bash, I strongly recommend reading http://mywiki.wooledge.org/BashGuide

geirha
  • 46,101
2

Essentially you need to loop through every text file in a directory, then add a small string to the start. It's not hard when you break it down into two steps.

To add the string to the beginning of a file, the format would be this:

echo "50 $( cat file.txt )" > file.txt

If you get a cannot overwrite existing file error, you need to disable noclobber

set +o noclobber

Now you just need to drop that in a loop that loops through the files you want to alter.

for FILE in $( ls /mydata/ | grep txt$ ) ; do
  echo "${FILE}"
done

If that outputs all the files you want to alter correctly, add in the command to alter the files (as below). If not, alter the grep statement until it matches what you need.

for FILE in $( ls /mydata/ | grep txt$ ) ; do
  echo "50 $( cat ${FILE} )" > "${FILE}"
done

And if you want it done in one line:

for FILE in $( ls /mydata/ | grep txt$ ) ; do echo "50 $( cat ${FILE} )" > "${FILE}"; done

Edit

If you want the 50 on its own line, use printf along with \n instead of echo, as below.

for FILE in $( ls /mydata/ | grep txt$ ) ; do printf "50\n$( cat ${FILE} )" > "${FILE}"; done
TJ L
  • 396
2

Since you asked, commandlinefu.com lists a bunch of commands and tricks for use in the shell, and it has lots of stuff about text-file manipulation.

1

It's relatively straightforward to add text to the end of files. For BASH: echo 50 >> file.txt will append 50 to the end of of file.txt. Wrap that up in a for loop like so: for $FILE in 'ls' do echo 50 >> $FILE; done;for $FILE in * do echo 50 >> $FILE; done; will iterate over all the files in the current directory appending 50 to the end. Note that the single quotes are actually `, but that's the indicator for code markup here... blech. To add it to the top of each file, create a temporary file and echo 50 into it, then echo the contents of the file after that. Then rename the file to overwrite the original. Wrap it up in a script and you're set!

#!/bin/bash

echo "Adding 50 to each file in current directory."

for $FILE in *
do
[[ -f "$i" ]] || continue
echo "50" >> tmp
cat "$FILE" >> tmp
mv tmp "$FILE"
done

That should work, but run it on a test directory before anything important.

Edit: Updated the script as suggested in Mahesh's comment.