0

I have recently started working with Shell scripting. So, I am facing one issue that when i am taking filename as an input from user, then if I give spaces then it does not get handled with my code. Any answers for the same

My Code looks like this :

echo "---------------- Please provide the filename -------------------------"
read filename
if [[ $filename =~ [A-Za-z0-9]+[a-zA-Z0-9_.]*+$ ]]; then
    printf "some code "
else 
    printf "some code"
fi

Can anyone please help me that how can I handle space character so that if space is provided in input parameter then it should give some error .

Thanks

  • The *+ at the end of the regex is wrong. you can use * (zero-or-more) or + (one-or-more) here, but using both together the second modifier has no meaning. Also if you intend to check whether $filename contains ONLY those characters, you need to have ^ (beginning-of-line anchor) at the start of the regex. As it is your regex only checks if $filename contains one-or-more letters-or-digits somewhere in it. – cas Mar 31 '16 at 21:06
  • 2
    If you want to forbid spaces because they break your script, fix your script. Also note that if spaces break something, there are probably other characters that cause problems, starting with tabs. – Gilles 'SO- stop being evil' Mar 31 '16 at 23:17

2 Answers2

1

You can check that with regex:

Whole code would look like this:

if [[ $filename =~ \  ]]; then
    printf "error"
    exit(1)
elif [[ $filename =~ [A-Za-z0-9]+[a-zA-Z0-9_.]*+$ ]]; then
    printf "some code "
else 
    printf "some code"
fi
MatthewRock
  • 6,986
1

Why are you restricting the file name at all? On most file systems, Unix file names can contain any character except for NUL (\0) and forward slash (/). You're better off learning now how to handle unusual file names than to get in the habit of expecting only letters and digits like you've done, and get bitten later when you come across something unexpected.

I suggest doing some reading on how to handle file names with spaces and other odd characters.

The first tip is to always use double quotes around your variables. There are cases when you don't need to, but for a beginner, it's easier to just always do it. This alone will probably deal with the particular problem you're trying to solve right now.

The next thing I would recommend is to read up on and learn to love the find command, and it particular, its -exec operator. This makes it easy to do the right thing when operating on a whole directory tree of files. For instance, never do this:

for f in *; do
    do-something-with-a-file "$f"
done

This won't work properly if any of the files have spaces, tabs, or newlines in their names (yes file names can contain newlines!). Not only that, but it doesn't let you distinguish between files and directories.

Instead, do this:

find -maxdepth 1 -type f -exec do-something-with-a-file {} \;

The -maxdepth operator limits the results to just those in the current directory, -type f tells find that we only want files, not directories, and -exec somecommand {} \; executes somecommand once for each file, passing the file's name (properly quoted) in place of {}. The backslash before the semicolon is for the sake of the shell, so that the shell won't process the semicolon, and will instead pass it on to the find command.

This is just a quick start on properly handling file names. Please read a bit on the topic, and post more questions here if you get stuck.

P Daddy
  • 375
  • for f in * is fine for whitespace if uses of $f have "; it's things like for f in $( ls ) or files=$( ls ); ...; for f in $files that fail for whitespace and also sometimes globbing chars (unless disabled), as your link correctly explains. To be portable, specify the directory explicitly: find . -blahblah; find . avoids dash-filename issues, but so does for f in ./*. find includes dotfiles while * doesn't by default. If/when you need to distinguish file/dir/symlink/etc shell can do that with test / [ or [[ (both internal, so as efficient as find) – dave_thompson_085 Mar 31 '16 at 17:38