Treating space as newline character in bash - bash

I have written a bash just to display the name of all the files of a given directory but when I am running this it breaking the file name which has spaces.
if [ $# -eq 0 ]
then
echo "give a source directory in the command line argument in order to rename the jpg file"
exit 1
fi
if [ ! -d "$1" ]; then
exit 2
fi
if [ -d "$1" ]
then
for i in $(ls "$1")
do
echo "$i"
done
fi
I am getting the following thing when I run the bash script
21151991jatinkhurana_image
(co
py).jpg
24041991jatinkhurana_im
age.jpg
35041991jatinkhurana_image
.jpg
The thing that i have tried till now is resetting the IFS variable like IFS=$(echo -en "\t\n\0") but found no change....
If anyone know please help me.....

Do not loop through the result of ls. Parsing ls makes world worse (good read: Why you shouldn't parse the output of ls).
Instead, you can do make use of the *, that expands to the existing content in a given directory:
for file in /your/dir/*
do
echo "this is my file: $file"
done
Using variables:
for file in $dir/*
do
echo "this is my file: $file"
done

Related

For files in directory Bash [duplicate]

I'm trying to loop through files in a directory, where the directory is passed through as an argument. I currently have the following script saved in test.sh:
#!/bin/bash
for filename in "$1"/*; do
echo "File:"
echo $filename
done
And I am running the above using:
sh test.sh path/to/loop/over
However, the above doesn't output the files at the directory path/to/loop/over, it instead outputs:
File:
path/to/loop/over/*
I'm guessing it's interpreting path/to/loop/over/* as a string and not a directory. My expected output is the following:
File:
foo.txt
File:
bar.txt
Where foo.txt and bar.txt are files in the path/to/loop/over/ directory. I found this answer which suggested to add a /* after the $1, however, this doesn't seem to help (neither do these suggestions)
Iterate over content of directory
Compatible answer (not only bash)
As this question is tagged shell, there is a POSIX compatible way:
#!/bin/sh
for file in "$1"/* ;do
[ -f "$file" ] && echo "Process '$file'."
done
Will be enough (work with filenames containing spaces):
$ myscript.sh /path/to/dir
Process '/path/to/dir/foo'.
Process '/path/to/dir/bar'.
Process '/path/to/dir/foo bar'.
This work well by using any posix shell. Tested with bash, ksh, dash, zsh and busybox sh.
#!/bin/sh
cd "$1" || exit 1
for file in * ;do
[ -f "$file" ] && echo "Process '$file'."
done
This version won't print path:
$ myscript.sh /path/to/dir
Process 'foo'.
Process 'bar'.
Process 'foo bar'.
Some bash ways
Introduction
I don't like to use shopt when not needed... (This change standard
bash behaviours and make script less readables).
There is an elegant way for doing this by using standard bash, without requirement of shopt.
Of course, previous answer work fine under bash, but. There are some
interresting way for making your script more powerfull, flexible, pretty, detailed...
Sample
#!/bin/bash
die() { echo >&2 "$0 ERROR: $#";exit 1;} # Emergency exit function
[ "$1" ] || die "Argument missing." # Exit unless argument submitted
[ -d "$1" ] || die "Arg '$1' is not a directory." # Exit if argument is not dir
cd "$1" || die "Can't access '$1'." # Exit unless access dir.
files=(*) # All files names in array $files
[ -f "$files" ] || die "No files found." # Exit if no files found
for file in "${files[#]}";do # foreach file:
echo Process "$file" # Process file
done
Explanation: considering globbing vs real files
When doing:
files=(/path/to/dir/*)
variable $files becomes an array containing all files contained under /path/to/dir/:
declare -p files
declare -a files=([0]="/path/to/dir/bar" [1]="/path/to/dir/baz" [2]="/path/to/dir/foo")
But if nothing match glob pattern, star won't be replaced and array become:
declare -p files
declare -a files=([0]="/path/to/dir/*")
From there. looking for $files is like looking for ${files[0]} ie: first field in array. So
[ -f "$files" ] || die "No files found."
will execute die function unless first field of array files is a file ([ -e "$files" ] to check for existing entry, [ -d "$files" ] to check for existing directory, ans so on... see man bash or help test).
But you could do replace this filesystem test by some string based test, like:
[ "$files" = "/path/to/dir/*" ] && die "No files found."
or, using array length:
((${#files[#]}==1)) && [ "${files##*/}" = "*" ] && die "No files found."
Dropping paths by using Parameter expansion:
For suppressing path from filenames, instead of cd $path you could do:
targetPath=/path/to/dir
files=($targetPath/*)
[ -f "$files" ] || die "No files found."
Then:
declare -p files
declare -a files=([0]="/path/to/dir/bar" [1]="/path/to/dir/baz" [2]="/path/to/dir/foo")
You could
printf 'File: %s\n' ${files[#]#$targetPath/}
File: bar
File: baz
File: foo
This would happen if the directory is empty, or misspelled. The shell (in its default configuration) simply doesn't expand a wildcard if it has no matches. (You can control this in Bash with shopt -s nullglob; with this option, wildcards which don't match anything are simply removed.)
You can verify this easily for yourself. In a directory with four files,
sh$ echo *
a file or two
sh$ echo [ot]*
or two
sh$ echo n*
n*
And in Bash,
bash$ echo n*
n*
bash$ shopt -s nullglob
bash$ echo n*
I'm guessing you are confused about how the current working directory affects the resolution of directory names; maybe read Difference between ./ and ~/

Can not locate a file in a bash script?

I am running a shell script which expects a file in a directory but I can not seem to locate it.
This is my shell script
#!/usr/bin/env bash
# expects a file to be present in current directory called INPUT_FILE
# this is the value set in the jenkins config
if [ ! -f INPUT_FILE ] ;then
echo "file ${INPUT_FILE} does not exist"
exit 1
fi
And in windows I am running a shell script from a directory like this
D:\scripts> ./all/script.sh
I tried to put INPUT_FILE.csv in scripts folder and also in all folder but it does not seem to work. Where should this file be present?
Make sure you have the correct filename.
Windows hides the extension of a file, when you look for INPUT_FILE.csv use
if [ ! -f INPUT_FILE.csv ] ;then
echo "file INPUT_FILE.csv does not exist"
exit 1
fi
You tried to use the variable INPUT_FILE. When you want this, try
input_file="INPUT_FILE.csv"
if [ ! -f "${input_file}" ]; then
echo "file ${input_file} does not exist"
exit 1
fi
Also note that bash is case sensitive, so INPUT_FILE.csv is different from input_file.csv.
It's better to list files first to verify the extension and all file names in the directory then check for the existence of the files.
#!/usr/bin/env bash
ALL_FILES=$(ls -I "*.sh") # This will list all file except .sh
echo "Files in current Directory $ALL_FILES"
INPUT_FILE="INPUT_FILE" # or INPUT_FILE="INPUT_FILE.csv"
if [ ! -f $INPUT_FILE ] ;then
echo "file ${INPUT_FILE} does not exist"
exit 1
else
echo "file exist ${INPUT_FILE}"
exit 0
fi
The first advantage, It will list all the file and the second one, If exist you will get the output.

how to check if a file exist and is a text file?

Hi everyone I need to check if a file exist with a shell script. I did some digging and ended up with this syntax but I'm not sure why it isn't working
(please bear in mind that you are talking to beginner)
I've found that you can add -e for example to check if it exist but I didn't get where these shortcuts came form or their names
#! /bin/bash
if [ "$#" = "1" ]
then
if [ -e $($1) ] && [ -f $($1) ]
then echo 'the file exists'
fi
fi
In idiomatic Bash:
#!/usr/bin/env bash
if [[ -f "${1-}" ]]
then
echo 'the file exists'
fi
Correct shebang
[[ rather than [
-f implies -e
No need for semicolons or single-use variables.
Please keep in mind that this does not tell you whether the file is a text file. The only "definition" of a text file as opposed to any other file is whether it contains only printable characters, and even that falls short of dealing with UTF BOM characters and non-ASCII character sets. For that you may want to look at the non-authoritative output of file "${1-}", for example:
$ file ~/.bashrc
/home/username/.bashrc: ASCII text
More in the Bash Guide.
#!/bin/bash
if [ "$#" == 1 ]; then
if [[ -e "$1" && -f "$1" ]]; then
echo 'The file exists';
fi
fi
You should put every conditional && between [[ ]] symbols otherwise it will be interpreted as execute if success.
#! /bin/sh
FILE=$1 # get filename from commandline
if [ -f $FILE ]; then
echo "file $FILE exists"
fi
See the fine manual page of test commands, which are built-in in the different shells: man test; man sh; man bash
You will also find many shell primers which explain this very nicely.
Or see bash reference manual: https://www.gnu.org/software/bash/manual/bash.pdf

Bash script not recognizing file

I am attempting to write a bash script. In a test, I wrote a script to check for the existence of test.txt. However, no matter how many times I try to change the formatting, the code still does not recognize the file.
while [ "$INPUT" != "quit" ]; do
read INPUT
COMMANDFILE=test.txt
if [ -f $COMMANDFILE ]; then
echo "Found file!"
fi
done
I am 100% positive text.txt exists and is in the same folder as my script.
in this case I would add some debug lines to my script to make sure my thinking is correct. For instance:
while [ "$INPUT" != "quit" ]; do
read INPUT
COMMANDFILE=test.txt
echo "debug: now I'm in $( pwd ) directory. dir listing:"
ls -la
if [ -f $COMMANDFILE ]; then
echo "Found file!"
fi
done
also, please note that linux filenames are case sensitive (meaning you can have test.txt and TeSt.txt in the same directory). So, for instance if you have the file named TEST.TXT, [ -f test.txt ] will evaluate to false (unless test.txt exists as well)

Checking the input arguments to script to be empty failed in bash script

This a small bash program that is tasked with looking through a directory and counting how many files are in the directory. It's to ignore other directories and only count the files.
Below is my bash code, which seems to fail to count the files specifically in the directory, I say this because if I remove the if statement and just increment the counter the for loop continues to iterate and prints 4 in the counter (this is including directories though). With the if statement it prints this to the console.
folder1 has files
Looking at other questions I think the expression in my if statement is right and I am getting no compilation errors for syntax or another problems.
So I just simply dumbfounded as to why it is not counting the files.
#!/bin/bash
folder=$1
if [ $1 = empty ]; then
folder=empty
counter=0
echo $folder has $counter files
exit
fi
for d in $(ls $folder); do
if [[ -f $d ]]; then
let 'counter++'
fi
done
echo $folder has $counter files
Thank you.
Your entire script could be very well simplified as below with enhancements made. Never use output of ls programmatically. It should be used only in the command-line. The -z construct allows to you assert if the parameter following it is empty or non-empty.
For looping over files, use the default glob expansion provided by the shell. Note the && is a short-hand to do a action when the left-side of the operand returned a true condition, in a way short-hand equivalent of if <condition>; then do <action>; fi
#!/usr/bin/env bash
[ -z "$1" ] && { printf 'invalid argument passed\n' >&2 ; exit 1 ; }
shopt -s nullglob
for file in "$1"/*; do
[ -f "$file" ] && ((count++))
done
printf 'folder %s had %d files\n' "$1" "$count"

Resources