I am using ubuntu, fluxbox, pcmanfm as filemanager, xmms2 as music player.
My goal: add songs to xmms2 playlist easily with pcmanfm.
I have this script that works for single files:
path= $1
if [ -d "$path" ]; then #if directory
xmms2 radd "$path"
else
if [ -e "$path" ]; then #if not directory, but file
xmms2 add "$path"
fi
fi
I also want to have ability to add group of files
I mean select all of them and then rigth-click -> open with -> xmms2_add_script
I thougth that same code in loop should work (if pcmanfm passes just more then one argument):
args=("$#")
for path in $args; do
if [ -d "$path" ]; then
xmms2 radd "$path"
else
if [ -e "$path" ]; then
xmms2 add "$path"
fi
fi
done
but it does not work.
(I know that there is some problem running for loop through filenames with whitespaces, so tried only non-whitespaced files.)
I tried loging the output adding this
echo date >> /home/me/output.txt
echo xmms2 radd "$path" >> /home/me/output.txt
in if statements.
It seems that program is called only once when I try adding group of files.
Maybe someone knows how pcmanfm opens multiple files with some program?
(I guess other programs does it same way)
Or maybe someone just know how can I achieve my goal with a bash script?
Just in case: to add item to xmms2 playlist "xmms2 radd directory_name" or "xmms2 add file_name"
I have only basic understanding of bash so would be nice if answers wouldn't for expirienced bash programmers :)
Change your for loop to this:
for path in "${args[#]}"; do
The for loop loops over its arguments, your args variable is an array, but bash only sees the first element when you do $args.
Greg's Bash FAQ/Wiki: How can I use array variables?
This is actually how I would write that to be more readable:
for x in "$#"; do
[[ -d $x ]] && xmms2 radd "$x"
[[ -f $x ]] && xmms2 add "$x"
done
Related
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
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"
How, in BASH, I could check if a given argument to a script is a "commands name"?
For example: I know that you can check if a path is a folder with [[ -d $path ]] or if it is plain file with [[ -f $path ]].
I want that my ./script will only accept commands name.
With [[ -f "$path" && -x "$path" ]] you can check if it is a file and it has execution permissions, you can see the full list of expressions in man test.
This way you check if the argument can be executed directly from the shell (for example: if <command> is ls this return Yes, if <command> is las this will return No).
if [[ `which <command> &> /dev/null` ]]; then
echo "Yes";
else
echo "No";
fi
With a simpler [[ -f $path && -x $path ]] you can check if $path can be executed... but this does not mean that writing the "name of the command" in the shell, it will be executed (you have to make sure that the $path is in the $PATH environmental variable.
A simple script that uses the idea above and exit in the case the argument is not a command could be something like:
#!/bin/bash
if [[ `which $1 &> /dev/null` ]]; then
echo "Execute the script"
else
echo "Error! Usage: "`basename $0`" <command_name>"
fi
Tell if you need something different...
Hi if i understand you right you can try the following:
SCRIPTNAME=$(basename "$0") # in your case -> script
Now you can check this:
if [ SCRIPTNAME -eq "$SCRIPTNAME" ]
then
# your stuff here
fi
Or do you want something other?
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.
#!/bin/bash
for dir in /home/username/git/*/
do
for file in "$dir"/*
do
if [[ -f $file ]]
then
echo "$file"
fi
done
done
When I try to run it. I got
syntax error near unexpected toke' `do
'rocTest.sh: line 3: `do
Why?
Use "$file" (with quotes) consistently to deal with "problematic" file names; in particular if [[ -f $file ]] should be
if [[ -f "$file" ]] ...
Note that bash is not always in /bin (e.g. FreeBSD places it in /usr/local/bin); for wider portability, either use
#!/usr/bin/env bash
or #!/bin/sh and make sure to remove bash-isms (e.g. use checkbashisms on Debian/Ubuntu). E.g. write if test -f "$file" instead of [[ -f "$file" ]]