Test existence of files in shell - shell

I have a list of files and I would like to pipe to a command to test if each files exists
cat files.txt | command
Does it exist any command to do that ? Do I have to write a script ? Can you help me to write it ?
For example:
> cat files.txt
libs/cakephp/app_exp/views/elements/export-menu.ctp
libs/cron/prad_import.php
main/css/admin/remarketing-graph.css
main/images/dropd-arrow.png
main/includes/forms/export/export_menu.php
main/jquery/jquery/jquery.cookie.js
main/mvc/controllers/remarketing/prad_controller.php
main/mvc/controllers/remarketing/remarketing_controller.php
but some of this files doesn't exits, so I want to do
> cat files.txt | command
libs/cakephp/app_exp/views/elements/export-menu.ctp
main/css/admin/remarketing-graph.css
main/images/dropd-arrow.png
main/includes/forms/export/export_menu.php
main/jquery/jquery/jquery.cookie.js
that returns only the existing files

Are you really using #!/bin/sh? In what context? An old Unix env, or in modern, stripped-down env with minimal cmds?
Can you use #!/bin/bash or #!/bin/ksh? That will make it easier.
But in any shell this should work
while read line ; do if [ -f "$line" ] ; then echo "$line" ; fi ; done < files.txt
This should allow for file/paths with spaces in them, but if other odd chars are embedded in the filenames then more work maybe required.
IHTH

test -f "files.txt" && cat "files.txt" | command
Also
[[ -f "files.txt" ]] && cat "files.txt" | command # in BASH
take your pick. test is more portable.
Understanding that you want command to test for file existence, then you do not need a pipe at all. You can do something like this with a while loop:
while read file; do
if test -f "$file"; then
echo "the file exists" # or whatever you want to do
else
echo "the file does NOT exist" # or whatever you want to do
fi
done < "files.txt"
This will read the file line-by-line and test each file for existence. You can also read all filenames from files.txt into an array and then loop through the array if you prefer. And yes, the above can be a script.

Related

Comparing the file's existence from a file and in current directory using shell script

I have a file files.txt with content:
F1.txt
F2.txt
F3.txt
F4.txt
I need to read the file files.txt line by line, and check if it exists in the current directory, if it does, I need to append the date at the end of each of line of files.txt, so that the output should be
F1.txt16032017
F2.txt16032017
F3.txt16032017
F4.txt16032017
I have used following simple shell script.
#!/bin/bash
DT=`date +%d%m%Y`
while IFS=read -r line
do
if [ -f $line]
then
echo "$line$DT" > files.ok
else
echo "$line" > files.notok
fi
done < files.txt
It executes without any error, but does not provide expected output with date append. Can someone tell me if the file existence test is correct
The problem is with your file write operator > which creates a creates a new file on every successful case, you need to have used the >> operator which appends to the existing file.
A much neater approach to your code would be to do
#!/bin/bash
dateToday="$(date +%d%m%Y)"
while IFS= read -r file; do
[ -f "$file" ] && printf "%s\n" "$file$dateToday" >> files.OK || printf "%s\n" "$file" >> files.NOK
done < files.txt
What updates that I have made to improve the script,
Removed the outdated command substitution syntax using backticks `` and used the $(..) for running them.
Double-quoted the variables, lower-cased the local variables.
Fixed the file write operator from > to >>
Used a single line condition making use of the return code of the test ([]) operator. The command after && runs if the condition [ -f "$file" ] is successful and the command after || runs if the condition fails.

Reading a file line by line from variable

I'm working on a script and it isn't clear how read -r line knows which variable to get the data from.. I want to read line by line from the FILE variable.
Here is the script I'm working on:
#!/bin/bash
cd "/"
FILE="$(< /home/FileSystemCorruptionTest/*.chk)"
while read -r line
do
echo "$line" > /home/FileSystemCorruptionTest/`date +%Y_%m_%d_%H_%M_%S`_1.log
done
echo "" > /home/FileSystemCorruptionTest/Done
Since it looks like you want to combine multiple files, I guess that I would regard this as a legitimate usage of cat:
cat /home/FileSystemCorruptionTest/*.chk | while read -r line
do
echo "$line"
done > /home/FileSystemCorruptionTest/`date +%Y_%m_%d_%H_%M_%S`_1.log
Note that I moved the redirect out of the loop, to prevent overwriting the file once per line.
Also note that your example could easily be written as:
cat /home/FileSystemCorruptionTest/*.chk > /home/FileSystemCorruptionTest/`date +%Y_%m_%d_%H_%M_%S`_1.log
If you only actually have one file (and want to store it inside a variable), then you can use <<< after the loop:
while read -r line
do
echo "$line"
done <<<"$FILE" > /home/FileSystemCorruptionTest/`date +%Y_%m_%d_%H_%M_%S`_1.log
<<< "$FILE" has the same effect as using echo "$FILE" | before the loop but it doesn't create any subshells.
What you are requesting:
echo "${FILE}" | while read -r line …
But I think Tom's solution is better.

shell script to count readable files

How can I write a shell script file_readable which:
accepts some number of names as arguments,
checks each name to see if it is a regular file and readable, and
outputs a count of the number of such files.
For example:
$ sh file_readable /etc/fstab /etc/ssh/ssh_host_rsa_key /etc/does-not-exist
1
Of these, only /etc/fstab is likely to both exist and be readable.
So far I have put this together but it does not work correctly - can anybody help me please ?:
#!/bin/sh
for filename in "$#"
do
if test -f "$filename"
then echo | wc -l
else echo $?
fi
done
then echo | wc -l
If file exists and is a regular you print number of lines in empty string plus "\n", which is equal 1 always. Sound not quite usable, isn't it?
All you need is incrementing some counter and printing it in the end.
#!/bin/sh
readable_files=0
for filename in "$#"; do
if test -f "$filename"; then
readable_files=$(( readable_files + 1 ))
fi
done
echo "${readable_files}"

Unix shell for loop [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Unix for loop help please?
I am trying to list the names of all the files in a directory separated by a blank line. I was using a for loop but after trying a few examples, none really work by adding blank lines in between. Any ideas?
Is there any command which outputs only the first line of a file in unix? How could I only display the first line?
for i in ls
do
echo "\n" && ls -l
done
for i in ls
do
echo "\n"
ls
done
Use head or sed 1q to display only the first line of a file. But in this case, if I'm understanding you correctly, you want to capture and modify the output of ls.
ls -l | while read f; do
printf '%s\n\n' "$f"
# alternately
echo "$f"; echo
done
IFS="
"
for i in $(ls /dir/name/here/or/not)
do
echo -e "$i\n"
done
To see the first part of a file use head and for the end of a file use tail (of course). The command head -n 1 filename will display the first line. Use man head to get more options. (I know how that sounds).
Use shell expansion instead of ls to list files.
for file in *
do
echo "$file"
echo
if [ -f "$file" ];then
read firstline < "$file"
echo "$firstline" # read first line
fi
done

How can I read standard input in a loop in bash, and then append the text to a file?

Say I have a bash script as follows
while
read $f;
do
cat $f >> output.txt;
echo "aaa" >> output.txt;
done
Yet the second echo statement isn't executed. At all. What am I doing wrong?
I'm running this via
tail -f /var/log/somelog | ./script.sh
$f should not be empty. It's only supposed to output when tail notices a change in the file.
The variable $f is probably empty, and your script is hanging on a call to cat with no arguments. Did you want to say
while read f
instead of
while read $f
?

Resources