If statement to tell if a file is in a directory [duplicate]

Clash Royale CLAN TAG#URR8PPP
up vote
1
down vote
favorite
This question already has an answer here:
Delete all files in a directory whose name do not match a line in a file list
6 answers
I am writing a bash script and want it to tell me if the names of the files in a directory appear in a text file and if not, remove them.
Something like this:
counter = 1
numFiles = ls -1 TestDir/ | wc -l
while [$counter -lt $numFiles]
do
if [file in TestDir/ not in fileNames.txt]
then
rm file
fi
((counter++))
done
So what I need help with is the if statement that is still pseudo code.
bash shell-script scripting
marked as duplicate by don_crissti, terdonâ¦
StackExchange.ready(function()
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();
);
);
);
Mar 16 at 12:54
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
add a comment |Â
up vote
1
down vote
favorite
This question already has an answer here:
Delete all files in a directory whose name do not match a line in a file list
6 answers
I am writing a bash script and want it to tell me if the names of the files in a directory appear in a text file and if not, remove them.
Something like this:
counter = 1
numFiles = ls -1 TestDir/ | wc -l
while [$counter -lt $numFiles]
do
if [file in TestDir/ not in fileNames.txt]
then
rm file
fi
((counter++))
done
So what I need help with is the if statement that is still pseudo code.
bash shell-script scripting
marked as duplicate by don_crissti, terdonâ¦
StackExchange.ready(function()
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();
);
);
);
Mar 16 at 12:54
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
Variable assignments should not have any spaces around the=sign:counter=1e.g. Also the values should be quoted if they contain spaces:foo="bar baz". To assign the output of a command to a variable, you need command substitution syntax:numFiles=$(ls -1 TestDir/ | wc -l).
â NickD
Mar 16 at 13:02
got the best answer here: stackoverflow.com/questions/49320683/â¦
â J. Tate
Mar 16 at 13:22
The best answer according to you...
â don_crissti
Mar 16 at 16:28
@J.Tate that answer is dangerous (the-fis risky) and will fail if your file names can be substrings of one another. So, if you have a file calledfoin your list, that command will deletedafore,foobar,yolofoyoetc etc. Also, if the file list can't be read for whatever reason, that command will delete every file in the directory. I'm afraid it really isn't a good answer.
â terdonâ¦
Mar 16 at 16:39
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
This question already has an answer here:
Delete all files in a directory whose name do not match a line in a file list
6 answers
I am writing a bash script and want it to tell me if the names of the files in a directory appear in a text file and if not, remove them.
Something like this:
counter = 1
numFiles = ls -1 TestDir/ | wc -l
while [$counter -lt $numFiles]
do
if [file in TestDir/ not in fileNames.txt]
then
rm file
fi
((counter++))
done
So what I need help with is the if statement that is still pseudo code.
bash shell-script scripting
This question already has an answer here:
Delete all files in a directory whose name do not match a line in a file list
6 answers
I am writing a bash script and want it to tell me if the names of the files in a directory appear in a text file and if not, remove them.
Something like this:
counter = 1
numFiles = ls -1 TestDir/ | wc -l
while [$counter -lt $numFiles]
do
if [file in TestDir/ not in fileNames.txt]
then
rm file
fi
((counter++))
done
So what I need help with is the if statement that is still pseudo code.
This question already has an answer here:
Delete all files in a directory whose name do not match a line in a file list
6 answers
bash shell-script scripting
edited Mar 16 at 12:28
asked Mar 16 at 12:21
J. Tate
1064
1064
marked as duplicate by don_crissti, terdonâ¦
StackExchange.ready(function()
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();
);
);
);
Mar 16 at 12:54
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
marked as duplicate by don_crissti, terdonâ¦
StackExchange.ready(function()
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();
);
);
);
Mar 16 at 12:54
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
Variable assignments should not have any spaces around the=sign:counter=1e.g. Also the values should be quoted if they contain spaces:foo="bar baz". To assign the output of a command to a variable, you need command substitution syntax:numFiles=$(ls -1 TestDir/ | wc -l).
â NickD
Mar 16 at 13:02
got the best answer here: stackoverflow.com/questions/49320683/â¦
â J. Tate
Mar 16 at 13:22
The best answer according to you...
â don_crissti
Mar 16 at 16:28
@J.Tate that answer is dangerous (the-fis risky) and will fail if your file names can be substrings of one another. So, if you have a file calledfoin your list, that command will deletedafore,foobar,yolofoyoetc etc. Also, if the file list can't be read for whatever reason, that command will delete every file in the directory. I'm afraid it really isn't a good answer.
â terdonâ¦
Mar 16 at 16:39
add a comment |Â
Variable assignments should not have any spaces around the=sign:counter=1e.g. Also the values should be quoted if they contain spaces:foo="bar baz". To assign the output of a command to a variable, you need command substitution syntax:numFiles=$(ls -1 TestDir/ | wc -l).
â NickD
Mar 16 at 13:02
got the best answer here: stackoverflow.com/questions/49320683/â¦
â J. Tate
Mar 16 at 13:22
The best answer according to you...
â don_crissti
Mar 16 at 16:28
@J.Tate that answer is dangerous (the-fis risky) and will fail if your file names can be substrings of one another. So, if you have a file calledfoin your list, that command will deletedafore,foobar,yolofoyoetc etc. Also, if the file list can't be read for whatever reason, that command will delete every file in the directory. I'm afraid it really isn't a good answer.
â terdonâ¦
Mar 16 at 16:39
Variable assignments should not have any spaces around the
= sign: counter=1 e.g. Also the values should be quoted if they contain spaces: foo="bar baz". To assign the output of a command to a variable, you need command substitution syntax: numFiles=$(ls -1 TestDir/ | wc -l).â NickD
Mar 16 at 13:02
Variable assignments should not have any spaces around the
= sign: counter=1 e.g. Also the values should be quoted if they contain spaces: foo="bar baz". To assign the output of a command to a variable, you need command substitution syntax: numFiles=$(ls -1 TestDir/ | wc -l).â NickD
Mar 16 at 13:02
got the best answer here: stackoverflow.com/questions/49320683/â¦
â J. Tate
Mar 16 at 13:22
got the best answer here: stackoverflow.com/questions/49320683/â¦
â J. Tate
Mar 16 at 13:22
The best answer according to you...
â don_crissti
Mar 16 at 16:28
The best answer according to you...
â don_crissti
Mar 16 at 16:28
@J.Tate that answer is dangerous (the
-f is risky) and will fail if your file names can be substrings of one another. So, if you have a file called fo in your list, that command will deleted afore, foobar, yolofoyo etc etc. Also, if the file list can't be read for whatever reason, that command will delete every file in the directory. I'm afraid it really isn't a good answer.â terdonâ¦
Mar 16 at 16:39
@J.Tate that answer is dangerous (the
-f is risky) and will fail if your file names can be substrings of one another. So, if you have a file called fo in your list, that command will deleted afore, foobar, yolofoyo etc etc. Also, if the file list can't be read for whatever reason, that command will delete every file in the directory. I'm afraid it really isn't a good answer.â terdonâ¦
Mar 16 at 16:39
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
3
down vote
Rather than saving the file list in a variable, loop over the names:
for name in TestDir/*; do
# the rest of the code
done
To test whether $name occurs in the fileNames.txt, use grep -q:
for name in TestDir/*; do
if ! grep -qxF "$name" fileNames.txt; then
echo rm "$name"
fi
done
The -F makes grep perform a string comparison rather than a regular expression match. With -q we get no output from grep, just an exit status that we can use with the if statement (true if the string was found but the exclamation mark inverts the sense of the test). The -x tells grep that the string $name needs to match a whole line, from start to finish, not just a part of a line.
I have protected the actual rm with echo. Run and make sure that the correct files gets deleted.
If the filenames are listed without the TestDir path, then change $name in the grep command to $name##*/:
for name in TestDir/*; do
if ! grep -qxF "$name##*/" fileNames.txt; then
echo rm "$name"
fi
done
This will look for the filename portion of the path in $name rather than the full path including TestDir.
add a comment |Â
up vote
2
down vote
With zsh:
expected=($(f)"$(<fileNames.txt)") || exit
cd TestDir || exit
actual=(*(D))
superfluous=($actual:)
if (($#superfluous))
echo These files are not in the expected list:
printf ' - %qn' $superfluous
read -q '?Do you want to delete them? ' && rm -rf -- $superfluous
add a comment |Â
up vote
2
down vote
Here's a working version using your approach:
#!/bin/bash
fileList="$1"
targetDir="$2"
## Read the list of files into an associative array
declare -A filesInFile
while IFS= read -r file; do
filesInFile["$file"]=1
done < "$fileList"
## Collect the files in the target dir
filesInDir=("$targetDir"/*);
for file in "$filesInDir[@]"; do
file=$file##*/; # get the name of the file; remove path
## If this file has no entry in the array, delete
if [[ -z "$filesInFile[$file]" ]]; then
echo "rm $file"
fi
done
Remove the echo to actually delete the files. Note that I am not checking if the number of files differs, since there didn't seem much point given that the number of files might be the same but you could still have files whose name isn't in the list.
add a comment |Â
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
Rather than saving the file list in a variable, loop over the names:
for name in TestDir/*; do
# the rest of the code
done
To test whether $name occurs in the fileNames.txt, use grep -q:
for name in TestDir/*; do
if ! grep -qxF "$name" fileNames.txt; then
echo rm "$name"
fi
done
The -F makes grep perform a string comparison rather than a regular expression match. With -q we get no output from grep, just an exit status that we can use with the if statement (true if the string was found but the exclamation mark inverts the sense of the test). The -x tells grep that the string $name needs to match a whole line, from start to finish, not just a part of a line.
I have protected the actual rm with echo. Run and make sure that the correct files gets deleted.
If the filenames are listed without the TestDir path, then change $name in the grep command to $name##*/:
for name in TestDir/*; do
if ! grep -qxF "$name##*/" fileNames.txt; then
echo rm "$name"
fi
done
This will look for the filename portion of the path in $name rather than the full path including TestDir.
add a comment |Â
up vote
3
down vote
Rather than saving the file list in a variable, loop over the names:
for name in TestDir/*; do
# the rest of the code
done
To test whether $name occurs in the fileNames.txt, use grep -q:
for name in TestDir/*; do
if ! grep -qxF "$name" fileNames.txt; then
echo rm "$name"
fi
done
The -F makes grep perform a string comparison rather than a regular expression match. With -q we get no output from grep, just an exit status that we can use with the if statement (true if the string was found but the exclamation mark inverts the sense of the test). The -x tells grep that the string $name needs to match a whole line, from start to finish, not just a part of a line.
I have protected the actual rm with echo. Run and make sure that the correct files gets deleted.
If the filenames are listed without the TestDir path, then change $name in the grep command to $name##*/:
for name in TestDir/*; do
if ! grep -qxF "$name##*/" fileNames.txt; then
echo rm "$name"
fi
done
This will look for the filename portion of the path in $name rather than the full path including TestDir.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Rather than saving the file list in a variable, loop over the names:
for name in TestDir/*; do
# the rest of the code
done
To test whether $name occurs in the fileNames.txt, use grep -q:
for name in TestDir/*; do
if ! grep -qxF "$name" fileNames.txt; then
echo rm "$name"
fi
done
The -F makes grep perform a string comparison rather than a regular expression match. With -q we get no output from grep, just an exit status that we can use with the if statement (true if the string was found but the exclamation mark inverts the sense of the test). The -x tells grep that the string $name needs to match a whole line, from start to finish, not just a part of a line.
I have protected the actual rm with echo. Run and make sure that the correct files gets deleted.
If the filenames are listed without the TestDir path, then change $name in the grep command to $name##*/:
for name in TestDir/*; do
if ! grep -qxF "$name##*/" fileNames.txt; then
echo rm "$name"
fi
done
This will look for the filename portion of the path in $name rather than the full path including TestDir.
Rather than saving the file list in a variable, loop over the names:
for name in TestDir/*; do
# the rest of the code
done
To test whether $name occurs in the fileNames.txt, use grep -q:
for name in TestDir/*; do
if ! grep -qxF "$name" fileNames.txt; then
echo rm "$name"
fi
done
The -F makes grep perform a string comparison rather than a regular expression match. With -q we get no output from grep, just an exit status that we can use with the if statement (true if the string was found but the exclamation mark inverts the sense of the test). The -x tells grep that the string $name needs to match a whole line, from start to finish, not just a part of a line.
I have protected the actual rm with echo. Run and make sure that the correct files gets deleted.
If the filenames are listed without the TestDir path, then change $name in the grep command to $name##*/:
for name in TestDir/*; do
if ! grep -qxF "$name##*/" fileNames.txt; then
echo rm "$name"
fi
done
This will look for the filename portion of the path in $name rather than the full path including TestDir.
edited Mar 16 at 13:08
answered Mar 16 at 12:34
Kusalananda
103k13201317
103k13201317
add a comment |Â
add a comment |Â
up vote
2
down vote
With zsh:
expected=($(f)"$(<fileNames.txt)") || exit
cd TestDir || exit
actual=(*(D))
superfluous=($actual:)
if (($#superfluous))
echo These files are not in the expected list:
printf ' - %qn' $superfluous
read -q '?Do you want to delete them? ' && rm -rf -- $superfluous
add a comment |Â
up vote
2
down vote
With zsh:
expected=($(f)"$(<fileNames.txt)") || exit
cd TestDir || exit
actual=(*(D))
superfluous=($actual:)
if (($#superfluous))
echo These files are not in the expected list:
printf ' - %qn' $superfluous
read -q '?Do you want to delete them? ' && rm -rf -- $superfluous
add a comment |Â
up vote
2
down vote
up vote
2
down vote
With zsh:
expected=($(f)"$(<fileNames.txt)") || exit
cd TestDir || exit
actual=(*(D))
superfluous=($actual:)
if (($#superfluous))
echo These files are not in the expected list:
printf ' - %qn' $superfluous
read -q '?Do you want to delete them? ' && rm -rf -- $superfluous
With zsh:
expected=($(f)"$(<fileNames.txt)") || exit
cd TestDir || exit
actual=(*(D))
superfluous=($actual:)
if (($#superfluous))
echo These files are not in the expected list:
printf ' - %qn' $superfluous
read -q '?Do you want to delete them? ' && rm -rf -- $superfluous
answered Mar 16 at 12:46
Stéphane Chazelas
280k53515847
280k53515847
add a comment |Â
add a comment |Â
up vote
2
down vote
Here's a working version using your approach:
#!/bin/bash
fileList="$1"
targetDir="$2"
## Read the list of files into an associative array
declare -A filesInFile
while IFS= read -r file; do
filesInFile["$file"]=1
done < "$fileList"
## Collect the files in the target dir
filesInDir=("$targetDir"/*);
for file in "$filesInDir[@]"; do
file=$file##*/; # get the name of the file; remove path
## If this file has no entry in the array, delete
if [[ -z "$filesInFile[$file]" ]]; then
echo "rm $file"
fi
done
Remove the echo to actually delete the files. Note that I am not checking if the number of files differs, since there didn't seem much point given that the number of files might be the same but you could still have files whose name isn't in the list.
add a comment |Â
up vote
2
down vote
Here's a working version using your approach:
#!/bin/bash
fileList="$1"
targetDir="$2"
## Read the list of files into an associative array
declare -A filesInFile
while IFS= read -r file; do
filesInFile["$file"]=1
done < "$fileList"
## Collect the files in the target dir
filesInDir=("$targetDir"/*);
for file in "$filesInDir[@]"; do
file=$file##*/; # get the name of the file; remove path
## If this file has no entry in the array, delete
if [[ -z "$filesInFile[$file]" ]]; then
echo "rm $file"
fi
done
Remove the echo to actually delete the files. Note that I am not checking if the number of files differs, since there didn't seem much point given that the number of files might be the same but you could still have files whose name isn't in the list.
add a comment |Â
up vote
2
down vote
up vote
2
down vote
Here's a working version using your approach:
#!/bin/bash
fileList="$1"
targetDir="$2"
## Read the list of files into an associative array
declare -A filesInFile
while IFS= read -r file; do
filesInFile["$file"]=1
done < "$fileList"
## Collect the files in the target dir
filesInDir=("$targetDir"/*);
for file in "$filesInDir[@]"; do
file=$file##*/; # get the name of the file; remove path
## If this file has no entry in the array, delete
if [[ -z "$filesInFile[$file]" ]]; then
echo "rm $file"
fi
done
Remove the echo to actually delete the files. Note that I am not checking if the number of files differs, since there didn't seem much point given that the number of files might be the same but you could still have files whose name isn't in the list.
Here's a working version using your approach:
#!/bin/bash
fileList="$1"
targetDir="$2"
## Read the list of files into an associative array
declare -A filesInFile
while IFS= read -r file; do
filesInFile["$file"]=1
done < "$fileList"
## Collect the files in the target dir
filesInDir=("$targetDir"/*);
for file in "$filesInDir[@]"; do
file=$file##*/; # get the name of the file; remove path
## If this file has no entry in the array, delete
if [[ -z "$filesInFile[$file]" ]]; then
echo "rm $file"
fi
done
Remove the echo to actually delete the files. Note that I am not checking if the number of files differs, since there didn't seem much point given that the number of files might be the same but you could still have files whose name isn't in the list.
answered Mar 16 at 12:50
terdonâ¦
122k28229400
122k28229400
add a comment |Â
add a comment |Â
Variable assignments should not have any spaces around the
=sign:counter=1e.g. Also the values should be quoted if they contain spaces:foo="bar baz". To assign the output of a command to a variable, you need command substitution syntax:numFiles=$(ls -1 TestDir/ | wc -l).â NickD
Mar 16 at 13:02
got the best answer here: stackoverflow.com/questions/49320683/â¦
â J. Tate
Mar 16 at 13:22
The best answer according to you...
â don_crissti
Mar 16 at 16:28
@J.Tate that answer is dangerous (the
-fis risky) and will fail if your file names can be substrings of one another. So, if you have a file calledfoin your list, that command will deletedafore,foobar,yolofoyoetc etc. Also, if the file list can't be read for whatever reason, that command will delete every file in the directory. I'm afraid it really isn't a good answer.â terdonâ¦
Mar 16 at 16:39