I'm writing my own package manager for vim / zsh / tmux
Now I want to check if the repo is already there before try to download
I got the function to clone the repo from github
function zsh_add_plugin() {
PLUGIN_NAME=$(echo $1 | cut -d "/" -f 2)
git clone "https://github.com/$1.git" "$ZDOTDIR/$PLUGIN_NAME"
}
and I got a list with the plugins
zsh_plugins=(
'hlissner/zsh-autopair'
'zsh-users/zsh-completions'
'romkatv/powerlevel10k'
'zsh-users/zsh-syntax-highlighting'
'zsh-users/zsh-autosuggestions'
'zsh-users/zsh-completions'
)
I could do now
for i in $zsh_plugins;
do zsh_add_plugin $i;
done
but I would like to check if it's already available
I tried like this but withoud success
for i in $zsh_plugins;
if [ ! -d "'$ZDOTDIR'/'$i'" ]; then
do zsh_add_plugin $i;
fi
done
getting this error
zsh: parse error near `zsh_add_plugin'
I hope someone could help
I tried also like that
for i in $zsh_plugins
do
if [ ! -d "$ZDOTDIR/$i" ]; then
zsh_add_plugin $i;
fi
done
I'ts not working properly.
The loop doesnt check if the repo is available
and im getting the errors
fatal: destination path '.....' already exists and is not an empty directory.
Move the do to the for loop
for i in $zsh_plugins
do
if [ ! -d "'$ZDOTDIR'/'$i'" ]; then
zsh_add_plugin $i;
fi
done
Related
I have the following bash script I want to use as my "standard browser" with xdg-open.
It should prompt dmenu for me to choose the browser to open the url in.
Now xdg-open passes the url as an argument to the program (I suppose) and as I'm cycling through an array of browsers using the # symbol, it confuses this one with the argument (url) and errors on the dmenu command.
Is there a workaround to this problem or am I doing something completely wrong? --This problem was solved
#!/usr/bin/env bash
set -euo pipefail
_path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo ".")")" && pwd)"
if [[ -f "${_path}/_dm-helper.sh" ]]; then
# shellcheck disable=SC1090,SC1091
source "${_path}/_dm-helper.sh"
else
# shellcheck disable=SC1090
echo "No helper-script found"
fi
# script will not hit this if there is no config-file to load
# shellcheck disable=SC1090
source "$(get_config)"
main() {
if [ -t 0 ]
then
_url=$1
else
read _url
fi
_browser=$(printf '%s\n' "${!browsers[#]}" | sort | ${DMENU} 'Select browser: ') # "$#") ## Thx to #jhnc
_command=${browsers[${_browser}]}
if [[ -n ${_url} ]];then
$_command $_url
fi
}
[[ "${BASH_SOURCE[0]}" == "${0}" ]] && main "$#"
(get config) loads the dmenu command:
DMENU=dmenu -i -l 20 -p
as well as the array of browsers:
declare -A browsers
browsers[brave]="brave-browser"
browsers[firefox]="firefox"
browsers[opera]="opera"
browsers[badwolf]="badwolf"
from my config file.
Originally if i ran xdg-open "https://" or if I clicked on a url in some other program, brave was opened with on that site.
Now after xdg-settings set default-web-browser dmenu-script.desktop with the following .desktop file:
[Desktop Entry]
Version=1.0
Name=Dmenu Browser Script
GenericName=Web Browser
# Gnome and KDE 3 uses Comment.
Comment=Access the Internet
Exec=$HOME/.local/bin/dmenu-browser %U
StartupNotify=true
Terminal=false
Icon=brave-browser
Type=Application
Categories=Network;WebBrowser;
MimeType=application/pdf;application/rdf+xml;application/rss+xml;application/xhtml+xml;application/xhtml_xml;application/xml;image/gif;image/jpeg;image/png;image/webp;text/html;text/xml;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ipfs;x-scheme-handler/ipns;
Actions=new-window;new-private-window;
[Desktop Action new-window]
Name=New Window
Exec=$HOME/.local/bin/dmenu-browser
[Desktop Action new-private-window]
Name=New Incognito Window
Exec=$HOME/.local/bin/dmenu-browser --incognito
It only works if I execute xdg-open from my command line. (I modified the .desktop file of brave-browser, because I had no clue how to write one.)
I have a problem which is iterating a file called for example: fileAndFolderPaths, and in other script I have to iterate this same file and check if each line is a file or folder path.
fileAndFolderPaths
/opt/sampleFolder
/opt/sampleFolder/aText.txt
/opt/otherFolder
Then my script file is something like that:
myScript.sh
#!/bin/bash
mapfile -t array < /tmp/fileAndFolderPaths
function checkIfFilesOrFolder(){
for i in "${array[#]}" do
if [ -f $i ]; then
echo -e "[Info] found the file: $i"
elif [ -d $i ]; then
echo -e "[Info] found the directory: $i"
else
echo -e "[Error] Nor directory or file were found based on this value: $i"
fi
done
}
checkIfFilesOrFolder
exit 0;
The problem is the check only works for the last line of the array created by the mapfile command. Any thoughts about that? I'm new to shell scripting so probably this is a really basic problem, but even so I wasn't able to fix it yet.
A couple of review suggestions, if you don't mind:
Don't need the global variable: pass the filename to the function and loop over the file:
checkIfFilesOrFolder() {
local file=$1
while IFS= read -r line; do
# test "$line" here ...
done < "$file"
}
checkIfFilesOrFolder /tmp/fileAndFolderPaths
I recommend using local for function variables, to minimize polluting the global namespace.
Always quote your variables, unless you're aware of exactly what expansions occur on them unqoted:
if [ -f "$line" ]; then ...
is there a reason you're using echo -e? The common advice is to use
printf '[Info] found the file: %s\n' "$line"
Interesting reading: Why is printf better than
echo?
Following my previous question which got closed— basically I have a script that check availability of packages on target server, the target server and the packages have been stored to an array.
declare -a prog=("gdebi" "firefox" "chromium-browser" "thunar")
declare -a snap=("beer2" "beer3")
# checkvar=$(
for f in "${prog[#]}"; do
for connect in "${snap[#]}"; do
ssh lg#"$connect" /bin/bash <<- EOF
if dpkg --get-selections | grep -qE "(^|\s)"$f"(\$|\s)"; then
status="[INSTALLED] [$connect]"
else
status=""
fi
printf '%s %s\n' "$f" "\$status"
EOF
done
done
With the help of fellow member here, I've made several fix to original script, script ran pretty well— except there's one problem, the output contain duplicate entries.
gdebi [INSTALLED] [beer2]
gdebi
firefox [INSTALLED] [beer2]
firefox [INSTALLED] [beer3]
chromium-browser [INSTALLED] [beer2]
chromium-browser [INSTALLED] [beer3]
thunar
thunar
I know it this is normal behavior, as for pass multiple server from snap array, making ssh travel to all the two server.
Considering that the script checks same package for two server, I want the output to be merged.
If beer2 have firefox packages, but beer3 doesn't.
firefox [INSTALLED] [beer2]
If beer3 have firefox packages, but beer2 doesn't.
firefox [INSTALLED] [beer3]
If both beer2 and beer3 have the packages.
firefox [INSTALLED] [beer2, beer3]
or
firefox [INSTALLED] [beer2] [beer3]
If both beer2 and beer3 doesn't have the package, it will return without extra parameter.
firefox
Sound like an easy task, but for the love of god I can't find how to achieve this, here's list of things I have tried.
Try to manipulate the for loops.
Try putting return value after one successful loops (exit code).
Try nested if.
All of the above doesn't seem to work, I haven't tried changing/manipulate the return string as I'm not really experienced with some text processing such as: awk, sed, tr and many others.
Can anyone shows how It's done ? Would really mean the world to me.
Pure Bash 4+ solution using associative array to store hosts the program is installed on:
#!/usr/bin/env bash
declare -A hosts_with_package=(["gdebi"]="" ["firefox"]="" ["chromium-browser"]="" ["thunar"]="")
declare -a hosts=("beer2" "beer3")
# Collect installed status
# Iterate all hosts
for host in "${hosts[#]}"; do
# Read the output of dpkg --get-selections with searched packages
while IFS=$' \t' read -r package status; do
# Test weather package is installed on host
if [ "$status" = "install" ]; then
# If no host listed for package, create first entry
if [ -z "${hosts_with_package[$package]}" ]; then
# Record the first host having the package installed
hosts_with_package["$package"]="$host"
else
# Additional hosts are concatenated as CSV
hosts_with_package["$package"]="${hosts_with_package[$package]}, $host"
fi
fi
# Feed the whole loop with the output of the dpkg --get-selections for packages names
# Packages names are the index of the hosts_with_package array
done < <(ssh "lg#$host" dpkg --get-selections "${!hosts_with_package[#]}")
done
# Output results
# Iterate the package name keys
for package in "${!hosts_with_package[#]}"; do
# Print package name without newline
printf '%s' "$package"
# If package is installed on some hosts
if [ -n "${hosts_with_package[$package]}" ]; then
# Continue the line with installed hosts
printf ' [INSTALLED] [%s]' "${hosts_with_package[$package]}"
fi
# End with a newline
echo
done
Instead of making several ssh connections in nested loops consider this change
prog=( mysql-server apache2 php ufw )
snap=( localhost )
for connect in ${snap[#]}; do
ssh $connect "
progs=( ${prog[#]} )
for prog in \${progs[#]}; do
dpkg -l | grep -q \$prog && echo \"\$prog [INSTALLED]\" || echo \"\$prog\"
done
"
done
Based on #Ivan answer
#!/bin/bash
prog=( "gdebi" "firefox" "chromium-browser" "thunar" )
snap=( "beer2" "beer3" )
# First, retrieve the list on installed program for each host
for connect in ${snap[#]}; do
ssh lg#"$connect" /bin/bash >/tmp/installed.${connect} <<- EOF
progs=( "${prog[#]}" )
for prog in \${progs[#]}; do
dpkg --get-selections | awk -v pkg=\$prog '\$1 == pkg && \$NF ~ /install/ {print \$1}'
done
EOF
done
# Filter the previous results to format the output as you need
awk '{
f = FILENAME;
gsub(/.*\./,"",f);
a[$1] = a[$1] "," f
}
END {
for (i in a)
print i ":[" substr(a[i],2) "]"
}' /tmp/installed.*
rm /tmp/installed.*
Example of output :
# With prog=( bash cat sed tail something firefox-esr )
firefox-esr:[localhost]
bash:[localhost,localhost2]
sed:[localhost,localhost2]
I found here, a code for Bash to be able to find a missing file, and this code works great because I wont be able to know the length of the sequenced files, so this is able to find the missing file without requiring me to input the last number in the sequence.
This is the code:
shopt -s extglob
shopt -s nullglob
arr=( +([0-9]).#(psd) )
for (( i=10#${arr[0]%.*}; i<=10#${arr[-1]%.*}; i++ )); do
printf -v f "%05d" $i;
[[ ! -f "$(echo "$f".*)" ]] && echo "$f is missing"
done
And it works in both terminal and iTerm.
BUT, when used in my Applescript it always reply with file 00000 is missing, when it is not:
set AEPname to "AO-M1P8"
set RENDERfolder to quoted form of POSIX path of "Volumes:RAID STORAGE:CACHES:RENDERS:AE"
set ISAEDONE to do shell script "cd /Volumes/RAID\\ STORAGE/CACHES/RENDERS/AE/AO-M1P8/
#!/bin/bash
shopt -s extglob
shopt -s nullglob
arr=( +([0-9]).#(psd) )
for (( i=10#${arr[0]%.*}; i<=10#${arr[-1]%.*}; i++ )); do
printf -v f \"%05d\" $i;
[[ ! -f \"$(echo \"$f\".*)\" ]] && echo \"$f is missing\"
done
"
display dialog ISAEDONE as text
(*
if ISAEDONE contains "is missing" then
display dialog "FILE IS MISSING"
else
display dialog "ALL FINE"
end if
*)
What I am doing wrong or is there an easier way to accomplish this?
Thanks in advance.
Screenshot
UPDATE
Seems like the way I was doing it, makes the shell unable to get the directory of the files, If I do manually input the directory, seems like it should work, but now I am getting a new kind of error:
sh: line 6: arr: bad array subscript
sh: line 6: arr: bad array subscript
Strange since I don't get this error when manually pasting the code into terminal.
I updated the code.
I'm getting errors when trying to parse a .env file I have, but I have no way of figuring out where it's erring out. Is there an easy way to lint/validate the file, online or otherwise?
Many thanks!
You can try https://github.com/dotenv-linter/dotenv-linter.
It's a lightning-fast linter for .env files. Written in Rust.
It depends on the syntax you are using. Looking at the Docker and NPM documentation, different tools seem to have a different scope on what they are able to parse.
I use a simple grep to validate if I have a <key>=<value> pattern, where key and value are non-empty. You can adapt the patterns to match your context, ensuring upper case keys for example.
#!/bin/bash
for envfile in $(find . -maxdepth 1 -type f -name '.env.*'); do
for line in $(cat ${envfile}); do
# exclude comments
if [[ "${line:0:1}" == "#" ]]; then
continue
fi
match_line=$(echo ${line} | grep -E "^[A-Za-z0-9_].+=.+$")
if [[ ${match_line} == "" ]]; then
echo "Error in file: ${envfile}: line: ${line}"
fi
done
done
Alternatively, look at your language loadenv library to see if you can catch specific parsing exceptions, if available, to narrow down the specific line that causes the error.