Shell Script Issue with Filenames Containing Spaces

Shell script issue with filenames containing spaces

you're actually adding redundant "'" (which your echo invocation shows)

try this:

#!/bin/sh
for f in *
do
ls "$f"
done

Shell script issue with directory and filenames containing spaces

Use find -print0 | xargs -0 to reliably handle file names with special characters in them, including spaces and newlines.

find /bishare/IRP_PROJECT/SFTP/ -type f -print0 |
xargs -0 ls -al > "$Temp_Path/File_Posted_$CURRENT_DATE.txt"

Alternatively, you can use find -exec which runs the command of your choice on every file found.

find /bishare/IRP_PROJECT/SFTP/ -type f -exec ls -al {} + \
> "$Temp_Path/File_Posted_$CURRENT_DATE.txt"

In the specific case of ls -l you could take this one step further and use the -ls action.

find /bishare/IRP_PROJECT/SFTP/ -type f -ls > "$Temp_Path/File_Posted_$CURRENT_DATE.txt"

You should also get in the habit of quoting all variable expansions like you mentioned in your post.

Shell script issue with filenames containing spaces while reading into an array

You're running the same command three separate times! And, the find command can take a long time to run.

I would take a look at your loop and see if you can do all of your steps in that single loop:

file_count=0
find . -type f -print0 | while read -d $'\0' file
do
((file_count+=1)) #Count the number of files processed
here be dragons...
echo "The '$file' file contains '$word' $word_count times"
done

The -print0 argument separates out the file names with the NUL character (One of the two characters that can't be contained in a file name. For extra credit, can you name the other?) You pipe this into a while read file to read the file name. The -d$'\0' tells the read to break up the words on the null character.

Not only does this take care of spaces in file names, but also tabs, double spaces, character returns, new lines, and almost anything else that can be tossed into the mix. You're guaranteed that you are reading one and only one file name no matter how funky that file name is.

Piping output of a command into a while read statement is a fairly efficient operation. It can go in parallel. That is, while the output of the command is being piped, the while loop is executing. Take a good look at this structure of this loop because you will be seeing it over and over again in your shell scripts.

The ((...)) is a mathematical operation.

The here be dragons... is where you fill in the logic to get the information you need. After all, it is a homework assignment. However, it looks like you have a good handle on shell scripting.


If you have to have these two arrays, I would pipe the output of the find into an array, then use that array to put your information into the numarray and filearray. It's not efficient, but at least you aren't running the find command three separate times.

Linux Scripting with Spaces in Filenames

So after reading through the commentary, we decided that although it may not be the right answer for every scenario, the right answer for this specific scenario was to extract the pieces manually.

Because we are building this for a pre-built script passing to it, and we aren't updating that script any time soon, we can accept with certainty that this script will always receive a -i, -o, and -e flag, and there will be spaces between them, which causes all the pieces passed in to be stored in different variables in $*.

And we can assume that the text after a flag is the response to the flag, until another flag is referenced. This leaves us 3 scenarios:

  1. The variable contains one of the flags
  2. The variable contains the first piece of a parameter immediately after the flag
  3. The variable contains part 2+ of a parameter, and the space in the name was interpreted as a split, and needs to be reinserted.

One of the other issues I kept running into was trying to get string literals to equate to variables in my IF statements. To resolve that issue, I pre-stored all relevant data in array variables, so I could test $variable == $otherVariable.

Although I don't expect it to change, we also handled what to do if the three flags appear in a different order than we anticipate (Our assumption was that they list as i,o,e... but we can't see excatly what is passed). The parameters are dumped into an array in the order they were read in, and a parallel array tracks whether the items in slots 0,1,2 relate to i,o,e.

The final result still has one flaw: if there is more than one consecutive space in the filename, the whitespace is trimmed before processing, and I can only account for one space. But saying as we processed over 4000 files before encountering one with a space, I find it unlikely with the naming conventions that we would encounter something with more than one space.

At that point, we would have to be stepping in for a rare intervention anyways.

Final code change is as follows:

#!/bin/bash
IFS='|'

position=-1
ioeArray=("" "" "")
previous=""
flagArr=("-i" "-o" "-e" " ")
ioePattern=(0 1 2)

#echo "for loop:"
for i in $*; do
#printf "%s\n" "$i"
if [ "$i" == "${flagArr[0]}" ] || [ "$i" == "${flagArr[1]}" ] || [ "$i" == "${flagArr[2]}" ]; then
((position += 1));
previous=$i;
case "$i" in
"${flagArr[0]}")
ioePattern[$position]=0
;;
"${flagArr[1]}")
ioePattern[$position]=1
;;
"${flagArr[2]}")
ioePattern[$position]=2
;;
esac
continue;
fi
if [[ $previous == "-"* ]]; then
ioeArray[$position]=${ioeArray[$position]}$i;
else
ioeArray[$position]=${ioeArray[$position]}" "$i;
fi
previous=$i;

done

echo "extracting (${ioeArray[${ioePattern[0]}]}) to (${ioeArray[${ioePattern[1]}]}) with (${ioeArray[${ioePattern[2]}]}) encoding."

inputfile=""${ioeArray[${ioePattern[0]}]}"";
outputfile=""${ioeArray[${ioePattern[1]}]}"";
encoding=""${ioeArray[${ioePattern[2]}]}"";

deal with filename with space in shell

You shouldn't use ls in for loop.

$ ls directory 
file.txt 'file with more spaces.txt' 'file with spaces.txt'

Using ls:

$ for file in `ls ./directory`; do echo "$file"; done
file.txt
file
with
more
spaces.txt
file
with
spaces.txt

Using file globbing:

$ for file in ./directory/*; do echo "$file"; done 
./directory/file.txt
./directory/file with more spaces.txt
./directory/file with spaces.txt

So:

for file in "$rule"/*.gz; do
echo "$file"
#tar -xf *.gz

#mv a b.xml to ab.xml
done

Whitespace in filenames in shell script

Don’t make it more complicated than it is.

cat "$FILE"

That’s all you need. Note the quotes around the variable. They prevent the variable from being expanded and split at whitespace. You should always write your shell programs like that. Always put quotes around all your variables, unless you really want the shell to expand them.

for i in $pattern; do

That would be ok.

How to pass a file name containing spaces as an argument to a command-line program?

You should be able to quote the filename (eg. "file name"), or use an escape sequence (eg. file\< space >name).



Related Topics



Leave a reply



Submit