Check user input on "rm -i"? - bash

Is there a way to check the user's response to a rm -i execution?
I'd like to echo something depending on whether or not the user responded with y or n.
The command returns successfully regardless of the user's response, so this attempt did not work:
$ rm -i testfile.txt && echo "The file was deleted."
remove testfile.txt? n
The file was deleted.
My reasoning was that the echo part would only be executed if the rm part was successful, but obviously a n response also counts as successful execution.
I would also like to be able to vary the message depending on the answer. This code would do it, but it's not very pretty.
file=testfile.txt
touch $file
read -p "Are you sure (y/n)? " answer
if [[ $answer =~ ^[yY](es|ES)?$ ]]; then
rm $file
echo "Deleted file."
else
echo "Did nothing."
fi
Surely there must be a way to get the input to rm -i.
How?

You can check, if the file was actually deleted. Eg.
rm -i testfile.txt && [[ ! -e testfile.txt ]] && echo "The file was deleted."
If the rm is successful, then test, if the file does not exist [[ ! -e file ]] and only then display the message. It covers the case, when you try to remove the file that does not exist, since then the rm will return with the exit code different than 0.
In case you want to display messages for when the file was purposefully deleted or not deleted, plus extra info on error, then you can extend the previous code like so:
rm -i testfile.txt && {
[[ ! -e testfile.txt ]] && echo "The file was deleted." || echo "Ignored"
} || echo "Error"

Most of the problem with your attempt is that you are trying to accommodate too many possible inputs, or paradoxically limiting the input to specifically "yes" or "no" while excluding "yeah", "yup", "nope", etc. A simply y or n will do (in fact, the only distinction you need to make is between y and not-y).
read -p "Are you sure (y/n)? " answer
if [[ $answer = [yY]* ]]; then
rm -- "$file"
echo "Deleted file."
else
echo "Did nothing."
fi
If you like, you can use shopt -s nocasematch before the if statement so that you can simply write if [[ $answer = y* ]]; then to ignore the case of the user's actual input.
Your original question would require some hook provided by rm itself, which it does not do.

Related

Bash Variable assignment issue

Trying to learn about variable assignment and got a bit stuck
#!/usr/bin/env bash
([ -f first.txt ] && [ -f second.txt ] && rm first.txt &&
DELETE="File deleted") ||
DELETE="File not found";
echo "${DELETE}"
If first.txt is missing, I get the correct message of "File not found" however, if I then create another "first.txt" the rest of the script works in that it tests for it and deletes it, but the variable assignment does not appear to be working, or, it is being overwritten by the or command which should not be running if the file exist. Either way, I am not getting the "File deleted" message that I am expecting, simply a blank space. This works if I just echo the text, but I want to be able to assign it to a variable to be able to compile and send as an email alert. What is going on here?
With an if clause/statement
#!/usr/bin/env bash
if [[ -f first.txt && -f second.txt ]]; then
rm first.txt &&
delete="File deleted"
else
delete="File not found"
fi
printf '%s\n' "$delete"
See https://mywiki.wooledge.org/BashPitfalls#pf22

Check if a file exists on a remote server with spaces in path

I'm trying to write a script to send my music from my computer to my android phone via ssh but I'm having some difficulties. Here is the piece of code :
while read SONG
do
echo $SONG
ssh -qi ~/.ssh/key root#$ip [[ -f "/sdcard/Music/${SONG}" ]] && echo "File exists" || echo "File does not exist"
done < ~/.mpd/playlists/Blues.m3u
The goal is to check if the song is already in the phone, and if it's not I'll scp it (if it's there it is with the same relative path than in the .m3u file).
I always got sh: syntax error: 'Davis/Lost' unexpected operator/operand and I think it is because there is a space before Davis that I can't escape
(the first $SONG is Geater Davis/Lost Soul Man/A Sad Shade Of Blue.mp3)
I also tried this, same result
while read SONG
do
echo $SONG
SONG="/sdcard/Music/$SONG"
echo $SONG
ssh -qi ~/.ssh/key root#$1 [[ -f "$SONG" ]] && echo "File exists" || echo "File does not exist"
done < ~/.mpd/playlists/Blues.m3u
Ideas welcome !!!
ssh command accepts only one argument as an command, as described in synopsis of manual page:
SYNOPSIS
ssh [...] [user#]hostname [command]
You need to adhere with that if you want correct results. Good start is to put whole command into the quotes (and escape any inner quotes), like this:
ssh -qi ~/.ssh/key root#$1 "[[ -f \"$SONG\" ]] && echo \"File exists\" || echo \"File does not exist\""
It should solve your issue.

Bash + check for file exist with a path home ~

I haven't found anything to deal with this particular situation. Maybe there is a easy way that I'm overlooking instead of checking for a string to catch this scenario. When I check an input for existence of a file, if the input is ~/filecheck , this won't work. I get negative results while the file is in my home folder. Any suggestions for improvement to any part of the script I will definitely appreciate. I also have to use an input instead of a argument. Thanks for any help.
my test script
read -p "Enter: " input
echo $input
if [ -f $input ]; then
read -p "Do you REALLY want to delete this file?:" input2
if [[ $input2='y' || $input2 = 'Y' ]]
then
rm -f $input
elif [[ $input2='n' || $input2='N' ]]
then
exit
else
echo "Invaild Option"
exit
fi
else
echo Invaild Option!
exit
fi
Since you are entering input string as ~/filecheck shell doesn't expand tilde while using condition with -f in [ -f $input ]
You can use it this way but it is not recommended and potentially dangerous as arbitrary commands can be run by user:
if [[ -f $(bash -c "echo $input") ]]; then
echo "file exists"
fi
EDIT: As per the comments below to avoid risky bash -c you can use:
if [[ -f "${input/\~/$HOME}" ]]; then
echo "file exists"
fi
You can't have tilde expansion in this part of the program without using something based on eval—and you don't want to do that with user input. So, your poor-man solution will be to substitute any potential leading ~/ with the expansion of $HOME/. Here's the adaptation of your script in an arguably better style:
#!/bin/bash
read -e -p "Enter: " input
input=${input/#~\//$HOME/} # <--- this is the main idea of this answer (and it's rather poor)
echo "$input"
if [[ -f $input ]]; then
read -e -p "Do you REALLY want to delete this file? " input2
if [[ ${input2,,} = y ]]; then
rm -f -- "$input"
elif [[ ${input2,,} = n ]]; then
exit
else
echo "Invalid Option"
exit
fi
else
echo "Invalid Option!"
fi
exit
Now, out of curiosity, why are you spending time to make a wrapper around rm? you're making a clunky interface to an already existing program, without adding anything to it, only rendering it less powerful and less easy to use.
If all what you want it's to ask the user before deleting, you can use:
rm -i
This will give you appropriate error in the case file does not exist.

Bash script - Nested If Statement for If File Doesn't Exist

I'm trying to compile a script that will read user input, and check if the file after the y/n statement. Then it will make files executable. I think the problem with my script is conditional ordering but check it out yourself:
target=/home/user/bin/
cd $target
read -p "This will make the command executable. Are you sure? (y/n)" CONT
if [ "$CONT" == "y" ];
then
chmod +x $1
echo "File $1 is now executable."
else
if [ "$(ls -A /home/user/bin/)" ];
then
echo "File not found."
else
echo "Terminating..."
fi
fi
As I said, I need the script to scan for the file after the y/n statement is printed. The script works fine how it is but still gives the "file is now executable" even if the argument file doesn't exist (but just gives the standard system "cannot find file" message after the echo'd text).
Your script is mostly correct, you just need to check if the file exists first. Also, it's not the best practice to use cd in shell scripts and not needed here.
So re-writing it
#!/bin/bash
target="/home/user/bin/$1"
if [[ ! -f $target ]]; then
echo "File not found."
else
read -p "This will make the command executable. Are you sure? (y/n) " CONT
if [[ $CONT == "y" ]]; then
chmod +x "$target"
echo "File $1 is now executable."
else
echo "Terminating..."
fi
fi
To get an understanding:
Your script will take one argument (a name of a file).
You ask if you want to make that file executable.
If the answer is 'yes', you make the file executable.
Otherwise, you don't.
You want to verify that the file exists too?
I'm trying to understand your logic. What does this:
if [ "$(ls -A /home/user/bin/)" ];
suppose to do. The [ ... ] syntax is a test. And, it has to be one of the valid tests you see here. For example, There's a test:
-e file: True if file exists.
That mean, I can see if your file is under /home/user/bin:
target="/home/user/bin"
if [ -e "$target/$file" ] # The "-e" test for existence
then
echo "Hey! $file exists in the $target directory. I can make it executable."
else
echo "Sorry, $file is not in the $target directory. Can't touch it."
fi
Your $(ls -A /home/user/bin/) will produce a file listing. It's not a valid test like -e unless it just so happens that the first file in your listing is something like -e or -d.
Try to clarify what you want to do. I think this is something more along the lines you want:
#! /bin/bash
target="/home/user/bin"
if [ -z "$1" ] # Did the user give you a parameter
then
echo "No file name given"
exit 2
fi
# File given, see if it exists in $target directory
if [ ! -e "$target/$1" ]
then
echo "File '$target/$1' does not exist."
exit 2
fi
# File was given and exists in the $target directory
read -p"Do you want $target/$1 to be executable? (y/n)" continue
if [ "y" = "$continue" ]
then
chmod +x "$target/$1"
fi
Note how I'm using the testing, and if the testing fails, I simply exit the program. This way, I don't have to keep embedding if/then statements in if/then statements.

Unix find a file and then prompting to delete [duplicate]

This question already has answers here:
How do I prompt for Yes/No/Cancel input in a Linux shell script?
(37 answers)
Closed 3 years ago.
I'm currently learning Unix and have come across a question in a book that I'm trying to solve.
I'm trying to write a script that asks a user to enter a file name.
Then, the script needs to check for file existence. If the file does not exist, that script should display an error message and then exit the script.
If the file exists, the script should ask if the user wants to delete the file:
If the answer is yes or y, the script should remove the file.
If the answer is no or n, the script should exit from the script.
If the answer is neither yes nor no, the script should display an error message and exit from the script.
This what I have written so far but have come across with a few errors:
#!/bin/bash
file=$1
if [ -f $file ];
then
echo read -p "File $file existes,do you want to delete y/n" delete
case $delete in
n)
exit
y) rm $file echo "file deleted";;
else
echo "fie $file does not exist"
exit
fi
If anyone come explain where I have gone wrong it would be greatly appreciated
I'd suggest this form:
#!/bin/bash
file=$1
if [[ -f $file ]]; then
read -p "File $file exists. Do you want to delete? [y/n] " delete
if [[ $delete == [yY] ]]; then ## Only delete the file if y or Y is pressed. Any other key would cancel it. It's safer this way.
rm "$file" && echo "File deleted." ## Only echo "File deleted." if it was actually deleted and no error has happened. rm probably would send its own error info if it fails.
fi
else
echo "File $file does not exist."
fi
Also you can add -n option to your prompt to just accept one key and no longer require the enter key:
read -n1 -p "File $file exists. Do you want to delete? [y/n] " delete
You added echo before read and I removed it.
In it's simplest form, you could do the following:
$ rm -vi file
To give you an example:
$ mkdir testdir; touch testdir/foo; cd testdir; ls
foo
$ rm -vi bar
rm: cannot remove 'bar': No such file or directory
$ rm -vi foo
rm: remove regular empty file 'foo'? y
removed 'foo'

Resources