Shell scripting and ls -1 problem

Hey, I'm running knoppix and I'm trying to run a shell script to change multiple lines of text in multiple files

#!/bin/sh
for i in 'ls-1 test'
do
sed 's/bob/manny/'g $i > $i.0
mv $i.0 $i
done

Obviously this isn't the original file, but it's on another non-networked machine.

What happens is that the console returns

sed: invalid option -- 1 , gives me options for sed then mv complains about the -1

I tried removing the -1 from ls, instead sed complained about ls.

This seems like it should work, what did I do wrong?

To keep the forums high quality for all users, please take the time to format your posts correctly.

First of all, use Code Tags when you post any code or data samples so others can easily read your code. You can easily do this by highlighting your code and then clicking on the # in the editing menu. (You can also type code tags

```text
 and 
```

by hand.)

Second, avoid adding color or different fonts and font size to your posts. Selective use of color to highlight a single word or phrase can be useful at times, but using color, in general, makes the forums harder to read, especially bright colors like red.

Third, be careful when you cut-and-paste, edit any odd characters and make sure all links are working property.

Thank You.

The UNIX and Linux Forums

---------- Post updated at 00:12 ---------- Previous update was at 00:10 ----------

i've not checked your script... but it sould be ` (backtick) instead of '.

`ls -1 test`

and the -1 is not needed either...

There are a variety of little bugs in this script.

1) The single quotes around 'ls-1 test' cause that whole string to be in variable $i which is what upset sed. To execute a command they need to be in backticks. Subtle but very important.
2) The second single quote in the sed line is misplaced. I think "sed" needs a "-e" switch but I don't know your O/S.
3) Though it hasn't caused an issue here you will be well advised to not call a script "test" because it is the name of a unix command.
4) There are better, more robust and POSIX-compliant methods to achieve this result.
5) "ls-1" should be "ls -1". The space character after "ls" is mandatory.

#!/bin/sh
for i in `ls -1 test`
do
      sed -e 's/bob/manny/g' $i > $i.0
      mv $i.0 $i
done

Even after correcting that to

for i in `ls -1 test`  ## backticks, not apostrophes

it is still the wrong way to loop through files. Not only is ls unnecessary, but it will cause the script to fail if any filenames contain spaces. (Also, the -1 is unnecessary since the output is not going to a terminal.)

The correct way is:

for i in test/*

A more robust approach which preserves space characters in filenames and works for any number of files is:

#!/bin/sh
ls -1 mytest.sh | while read filename
do
      sed -e 's/bob/manny/g' "${filename}" > "${filename}.0"
      mv "${filename}.0" "${filename}"
done

While doing this I belatedly noticed that

ls-1 

should be

ls -1

(the space character after ls is mandatory).
Looking back, "cfajohnson" spotted this immediately.

That is less robust than my suggestion. It will fail if there is a newline (heaven forbid!) in a file name. It also uses an unnecessary external command.

It will also fail if there is leading or trailing whitespace in any filenames. Or if there are any backslashes.

The syntax I used will work no matter what pathological characters are in the filenames.

The -1 is not needed because the output of ls is not going to a terminal.

I think you meant:

ls test | while IFS= read -r filename

You should check that sed succeeded before wiping the original file:

   sed -e 's/bob/manny/g' "${filename}" > "${filename}.0" &&
   mv "${filename}.0" "${filename}"

Many good points.
Good point about checking result from "sed".
Leading or trailing whitespace and backslashes in filenames will indeed fox most scripts and some commercial backup software. Imho any such filenames should be detected and removed from the system forthwith.

I disagree with "for i in test/*" because it fails on AIX for example with long lists.

Ps. I do run a periodic detect and manual clean of weird filenames in user directories. Unix files such as "C:\user_had_brain_damage.txt" upset our backup software.

While I remember, I have read much good advice about not interfering with IFS which dates back to the roots of unix.

It is trivial to deal with those in a script.

Commercial software is often very badly written. Open source is usually much superior.

It's a nice sentiment, but spaces in filenames are so common that it would be impossible to remove all such instances without breaking some applications.

Are you using a POSIX shell? If not, it's irrelevant because it's non standard.

Get better backup software!

There are times when IFS must be changed. If it's left at the default, scripts can fail.

However, changes should be local and temporary.