开发者

bash script with ls $variable

I'm trying to get my script to ls all the files in the form "$variable".*

the parameter is always a file with the extension .001 I want to find all the files with the same name but different extension, eg $file.002, file.003 etc.开发者_开发知识库 eg.:

first="$1"
others=${first%.001}
ls $others"*"

My problem is the file is named file[success].mpg.001 and what gets fed to ls is file[success].mpg* which gives me ls: cannot access file[success].mpg*: No such file or directory because ls needs to see:

file\[success\].mpg*

I've been trying everything, the one thing I did notice is ls fed the parameter $1 works, but not if fed $file after I've done file=$1 . So I guess how do I change the variable into a parameter?


You could use bash's printf command to reformat the string. Furthermore you don't need to quote *:

#!/bin/bash
first="$1"
others=$(printf %q "${first%.001}")
ls $others*

printf %q reformats the string in a format that can be used as shell input (regarding to bash's man page).

edit regarding to a comment:
The above solution does not work with white spaces in file names. For those cases (as some other answers already mentioned) it's better not to use printf but to properly quote all variables:

#!/bin/bash
first="$1"
others="${first%.001}"
ls -- "$others"*


You should quote the variable, not the wildcard:

ls -- "$others"*

The double dash stops search for options so that this code should work even if others begins with a dash.

Note that ls is more often than not the wrong solution in scripts. Use it only if you really want to print the list, e.g. in long format:

ls -l -- "$others"*

If you want to print only the names, you don't need ls at all:

echo "$others"*

Unfortunately you cannot use -- with echo. If, however, you want an array of the file names, use

filenames=("$others"*)

And should you want to iterate over them, use

for filename in "$others"*


You're not too far off. My first fix is changing line 3 to the following:

ls -- "${others}".*

This will expand $others and allow the globbing to happen. It's the shells responsibility to expand the * to the list of all matching filenames. The list of filenames is then sent to ls. It sounds like in most cases ls will see something like this:

file1.001 file1.002 file1.003 ...

But, when no files are present, the shell passes the glob to ls and it will see asterisk:

file1.*

Thus, your line, ls $others"*" appends a literal asterisk which ls will see.

Unless you have a file name file1.* (with a literal asterisks), ls will fail.

Another option is to use basename:

first="$1"
others=`basename -- "$first" .001`
ls -- "${others}".*

Using basename gives you the advantage that it can remove directories, etc.

However, as others have pointed out, depending on what you're doing with the list of files, find may be better.

EDIT: The double-hyphen doesn't work on all *nix variants but tells the ls and basename commands that no other cli arguments follow. Quoting your variables may be a best practices but I prefer the simplicity of leaving them off unless the data isn't trusted. Know your data and quote appropriately.


Use find instead ls:

$ ls weg.*
ls: weg.*: No such file or directory
$ find . -name weg.\*
$
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜