Compare commits
76 Commits
v3.1.0
...
75e047d70e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75e047d70e | ||
|
|
742ec484a7 | ||
|
|
1b7262c0cd | ||
|
|
e387209c10 | ||
|
|
f5d59ec194 | ||
|
|
2ee1c935ac | ||
|
|
e41c1a4c51 | ||
|
|
60dfe19049 | ||
|
|
c32771a4ff | ||
|
|
080511d0bd | ||
|
|
d8bdfefdf1 | ||
|
|
5f5f9c0e71 | ||
|
|
30387a4f08 | ||
|
|
0c51363d86 | ||
|
|
043fbaef0b | ||
|
|
ed5587712e | ||
|
|
58cc76c317 | ||
|
|
e82ee06e1d | ||
|
|
bc8cb4a237 | ||
|
|
ae90a9f4c4 | ||
|
|
7e661ca2de | ||
|
|
9f22ed4304 | ||
|
|
1484b004be | ||
|
|
0a4206b890 | ||
|
|
02a1e25df2 | ||
|
|
7ca0a6fb88 | ||
|
|
25df408e37 | ||
|
|
3eab1f98d5 | ||
|
|
6c895b509a | ||
|
|
2ece711e1a | ||
|
|
39a7e7b40f | ||
|
|
6d5d872b71 | ||
|
|
128cfe8c87 | ||
|
|
e1c2705fdd | ||
|
|
368bc11acf | ||
|
|
a068d57ba5 | ||
|
|
ffee8c2e47 | ||
|
|
9ff5792790 | ||
|
|
6a2d9b0fee | ||
|
|
9b2c764181 | ||
|
|
3d5a5e7718 | ||
|
|
47e89b3b09 | ||
|
|
f0f80e2924 | ||
|
|
b08e457146 | ||
|
|
56e34bc346 | ||
|
|
e9e9993dfc | ||
|
|
ff4c6702b7 | ||
|
|
87dea45295 | ||
|
|
0abf481cf6 | ||
|
|
a75299f7b4 | ||
|
|
eeb87c5bfc | ||
|
|
4879b418db | ||
|
|
f944271488 | ||
|
|
4be2e5ea87 | ||
|
|
9d528a6491 | ||
|
|
bef205ae84 | ||
|
|
9e49e3e4d7 | ||
| 94e7e79c76 | |||
| 55e88bd018 | |||
|
|
18f1bc1543 | ||
|
|
0d7c7e9ab7 | ||
|
|
64fecf16fb | ||
| c2ca5f659c | |||
| 3248327e56 | |||
| fd984c4a16 | |||
| c2a0ef0bd2 | |||
| dc64123fd9 | |||
| affe6e1487 | |||
| 0237f8bf70 | |||
| d4db72260a | |||
| e980198c08 | |||
| 21c12865f5 | |||
| 5b9d7a983e | |||
| d7e6d81126 | |||
| 4a975db1c0 | |||
| c5a43a3942 |
30
LICENSE
30
LICENSE
@@ -1,11 +1,29 @@
|
||||
Copyright (c) <year> <owner>.
|
||||
Copyright 2013-2022 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
This is distributed with BSD-3-Clause license with the following terms and
|
||||
condition:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
112
README.md
112
README.md
@@ -1,3 +1,113 @@
|
||||
# profile
|
||||
This project aims to create an advanced bash profile. It includes some aliases,
|
||||
a customized prompt and several functions for different purposes. It's mostly
|
||||
targeted to system administrator but might satisfy some regular users.
|
||||
|
||||
bash profile repository
|
||||
## 1. Getting started
|
||||
Download and extract (or use git clone) the profile archive into your home
|
||||
directory. You will have to modify your ~/.bashrc and/or ~/.profile file to add
|
||||
at the end (preferably):
|
||||
```
|
||||
source <installpath>/profile/profile.sh
|
||||
```
|
||||
|
||||
It's not recommended to load that profile in /etc/profile as the users' .bashrc
|
||||
files might interfere with some aliases and functions defined in profile.
|
||||
|
||||
## 2. What's the purpose?
|
||||
profile is giving access to numerous functions, aliases and to an advanced
|
||||
prompt. Here is a non-exhaustive list of what we have:
|
||||
- A bar style prompt with hour, execution time and exit code of the last
|
||||
command;
|
||||
- clean: erase after confirmation any backup file, possibly recursively;
|
||||
- dwl: a curl/wget/fetch download wrapper;
|
||||
- pkgs: search for the given pattern in the installed packages name;
|
||||
- expandlist: usefull in scripts, it expand any expression using wildcards into
|
||||
the corresponding list of file and directories;
|
||||
- genpwd: generate one or more random secure password;
|
||||
- gpid: give the list of PID matching the given process name;
|
||||
- help: display the list of available function and basic use;
|
||||
- isipv4: tell if the given parameter is a valid IPv4 address;
|
||||
- isipv6: tell if the given parameter is a valid IPv6 address;
|
||||
- ku: kill all the processes owned by the given user name or ID;
|
||||
- mcd: create a directory and immediately move into it;
|
||||
- meteo: display weather forecast information;
|
||||
- myextip: get informations about your public IP;
|
||||
- ppg: look for the given patern in the running processes;
|
||||
- rain: console screensaver with rain effect;
|
||||
- rmhost: remove the given host (name or IP) to the list of SSH known host;
|
||||
- rmspc: in the current directory it replace all the spaces in filenames with a
|
||||
underscore caracter (or any other given in option);
|
||||
- setc: set locale on standard C;
|
||||
- setfr: set locale on French;
|
||||
- settrace: allow the debugging of any script by showing a backtrace in case of
|
||||
error;
|
||||
- setus: set locale on US English;
|
||||
- showinfo: display basic informations about the host;
|
||||
- ssr: root ssh login to the given host;
|
||||
- taz: a universal command to compress files and directories, possibly several
|
||||
at once;
|
||||
- utaz: a utility that smartly uncompress many archives at once, creating a
|
||||
directory only if needed;
|
||||
- ver: show profile version.
|
||||
|
||||
## 3. Configuration
|
||||
Some functions might have configurable default behaviour. You can create a
|
||||
profile.conf file to configure those default behaviour. You should have a look
|
||||
at the doc/profile.conf.example to see the list of available options. The
|
||||
configuration file is located in the same directory as profile.sh file.
|
||||
|
||||
## 4. Contact and more information
|
||||
### 4.1. New users
|
||||
This project is very new in terms of publication, and I have no idea of who will
|
||||
use it, if any does. If you use (or plan to use) ```profile```, I'll be very
|
||||
happy if you simply mail me to let me know, especially if you don't plan to
|
||||
contribute. If you plan to contribute, I'll be twice happier for sure!
|
||||
|
||||
### 4.2. Bugs
|
||||
**profile** bug tracker is hosted on its Gitea instance. Check the
|
||||
https://git.geoffray-levasseur.org/fatalerrors/profile page. If you find a bug,
|
||||
you can also submit a bug report to the maintainer mail address mentioned at
|
||||
the end of that document. A bug report may contain the command line parameters
|
||||
where the bug happens, OS details, the module that trigger it, if any, and the
|
||||
log file containing the error. Cygwin users: please note that bash
|
||||
implementation in Cygwin triggers regularly bugs on advanced code that triggers
|
||||
nothing with Linux or BSD. Please do not send synthax error bug repports if you
|
||||
didn't test the same code in the same conditions using a real Unix.
|
||||
|
||||
Please check the to-do list before sending any feature request, as it might
|
||||
have already be requested.
|
||||
|
||||
### 4.3. How to contribute?
|
||||
You are free to improve and contribute as you wish. If you have no idea what to
|
||||
do or want some direction, you can check the [to-do list](./doc/todo.md),
|
||||
containing desired future improvements. Make sure you always have the latest
|
||||
development version before starting your work.
|
||||
|
||||
It's heavily recommended to use git to obtain the latest copy of profile tree.
|
||||
Make sure your git configuration is correct in order to contribute. Please
|
||||
contact me to obtain push authorizations, or, if you want to submit a patch, you
|
||||
can send it by mail to the maintainer of init.sh.
|
||||
|
||||
Code written in Python or Perl might be accepted as long as it's not mobilizing
|
||||
a lot of dependencies (forget big framework). Anything that need the
|
||||
installation of packages not provided in minimal Debian or CentOS installation
|
||||
will be probably rejected.
|
||||
|
||||
If you want to make a financial contribution, please contact me by mail.
|
||||
|
||||
### 4.4. License, website, and maintainer
|
||||
Everything except configuration files is licensed under BSD-3 license. Please
|
||||
check license file allong this one.
|
||||
|
||||
Please check [https://www.geoffray-levasseur.org/profile](https://www.geoffray-levasseur.org/profile).
|
||||
Note that this website is still under construction and needs some more care.
|
||||
|
||||
You can mail author to fatalerrors \<at\> geoffray-levasseur \<dot\> org.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Documentation (c) 2021-2022 Geoffray Levasseur.
|
||||
|
||||
This file is distributed under3-clause BSD license. The complete license
|
||||
agreement can be obtained at: https://opensource.org/licenses/BSD-3-Clause
|
||||
|
||||
147
history.txt
Normal file
147
history.txt
Normal file
@@ -0,0 +1,147 @@
|
||||
------------------------------------------------------------------------------
|
||||
Initial version from Beyond Linux From Scratch by
|
||||
* James Robertson <jameswrobertson@earthlink.net>
|
||||
* Dagmar d'Surreal <rivyqntzne@pbzpnfg.arg>
|
||||
------------------------------------------------------------------------------
|
||||
Current version from Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
------------------------------------------------------------------------------
|
||||
Version history:
|
||||
------------------------------------------------------------------------------
|
||||
# 05/03/2026 v3.6.1
|
||||
Fix a typo in compress.sh
|
||||
|
||||
# 05/03/2026 v3.6.0
|
||||
Improved utaz to make it multiformat with lot of it
|
||||
Introduced ppu and ppn
|
||||
Improved update system
|
||||
|
||||
# 04/03/2026 v3.5.0
|
||||
rain has now configurable speed and color
|
||||
showinfo adapted to fastfetch, replacing neofetch
|
||||
|
||||
# 24/02/2022 v3.3.1
|
||||
Fixed version detection
|
||||
Added "busy" function
|
||||
Fixed use of library functions before it's loaded
|
||||
|
||||
# 28/11/2022 v3.3.0
|
||||
Initial version update support
|
||||
Changed versioning code
|
||||
Added installation path detection
|
||||
|
||||
# 28/11/2022 v3.2.3
|
||||
Made proper readme file, to improve
|
||||
|
||||
# 21/11/2022 v3.2.2
|
||||
Fixed taz compression level analysis
|
||||
Fixed typo in dpkgs
|
||||
|
||||
# 20/11/2022 v3.2.1
|
||||
Fix some messages
|
||||
Make dpkgs rpm aware (more to come)
|
||||
Removed version history from main script and revert declaration order
|
||||
Added required license information in all files
|
||||
Completed LICENSE file
|
||||
|
||||
# 18/11/2022 v3.2.0
|
||||
Created disp command for display and make use of it
|
||||
|
||||
# 10/11/2022 v3.1.1
|
||||
genpwd: test if password is doable
|
||||
|
||||
# 08/11/2022 v3.1.0
|
||||
Added password generator
|
||||
|
||||
# 07/11/2022 v3.0.1
|
||||
Added concatenation to rmspc
|
||||
Added ku
|
||||
Error managed in meteo
|
||||
|
||||
# 27/08/2022 v3.0.0
|
||||
Splitted everything in several files
|
||||
Added rain screensaver
|
||||
|
||||
# 29/07/2022 v2.8.2
|
||||
Added warning for non bash or zsh users
|
||||
|
||||
# 19/07/2022 v2.8.1
|
||||
Few cleanups, fixes and optimizations
|
||||
|
||||
# 24/06/2022 v2.8.0
|
||||
Added backtrace, error and settrace
|
||||
[bugfix] corrected showinfo
|
||||
|
||||
# 22/06/2022 v2.7.1
|
||||
[bugfix] few minor corrections
|
||||
Added help command
|
||||
|
||||
# 21/06/2022 v2.7.0
|
||||
Added isipv4 and isipv6 and use it in rmhost as an improvement
|
||||
Removed konsole save and restore not working
|
||||
|
||||
# 18/10/2021 v2.6.3
|
||||
Changed PS1 for status bar style version
|
||||
Few minor improvements
|
||||
|
||||
# 26/02/2021 v2.6.2
|
||||
[bugfix] taz: corrected bug with trailing slash on directories
|
||||
|
||||
# 25/12/2020 v2.6.1
|
||||
Add check on rmhost
|
||||
Improvements rmspc
|
||||
Created expendlist
|
||||
|
||||
# 24/10/2020 v2.6.0
|
||||
Added session save and restore for Konsole
|
||||
|
||||
# 11/09/2020 v2.5.3
|
||||
Few more aliases, improved code consistancy and typo,
|
||||
Improved utaz, removed showdiskmap, removed remaining French,
|
||||
Added license information for future publication
|
||||
|
||||
# 06/03/2020 v2.5.2
|
||||
Few aliases sorted out
|
||||
|
||||
# 05/03/2020 v2.5.1
|
||||
Language consistancy fix
|
||||
Added pigz support in taz
|
||||
|
||||
# 03/03/2020 v2.5.0
|
||||
Added command taz and rmspc
|
||||
Renamed auzip => utaz and improved it
|
||||
|
||||
# 02/03/2020 v2.4.0
|
||||
Added command auzip
|
||||
|
||||
# 31/01/2020 v2.3.2
|
||||
Figlet: changed default font to ansi_shadow
|
||||
|
||||
# 16/01/2020 v2.3.1
|
||||
[bugfix] non-interactive were blocked with some functions
|
||||
|
||||
# 08/01/2020 v2.3.0
|
||||
Added use of figlet and neofetch as a motd replace
|
||||
|
||||
# 16/12/2019 v2.2.0
|
||||
Added showinfo
|
||||
Primary write of showdiskmap
|
||||
|
||||
# 24/09/2019 v2.1.2
|
||||
[bugfix] bug in profile version display
|
||||
|
||||
# 23/09/2019 v2.1.1
|
||||
[bugfix] dpkgs
|
||||
|
||||
# 16/09/2018 v2.1.0
|
||||
Added rmhost, setc, setfr
|
||||
More locales management
|
||||
|
||||
# 04/02/2017 v2.0.1
|
||||
clean improvements (--shell)
|
||||
|
||||
# 24/10/2015 v2.0.0
|
||||
Added advanced functionnalities (clean, srr, etc.)
|
||||
|
||||
# 16/02/2013 v1.0.0
|
||||
Initial version
|
||||
|
||||
90
profile.conf
Executable file
90
profile.conf
Executable file
@@ -0,0 +1,90 @@
|
||||
[system]
|
||||
# System section is used to set Bash behavior and other system related
|
||||
# variables, such as the default pager, the terminal type, etc.
|
||||
# Set bash history
|
||||
HISTSIZE=50000
|
||||
HISTIGNORE="&:[bf]g:exit"
|
||||
|
||||
# Set default pager
|
||||
PAGER=less
|
||||
|
||||
# Set terminal colors behavior
|
||||
TERM=xterm-256color
|
||||
|
||||
[compress]
|
||||
# Section used by compress.sh
|
||||
|
||||
[debug]
|
||||
# Section used by debug.sh
|
||||
|
||||
[disp]
|
||||
# Section used by disp.sh
|
||||
# NO_COLOR=1 # Set to any value to disable colors in disp output
|
||||
|
||||
[filefct]
|
||||
# Section used by filefct.sh
|
||||
|
||||
[fun]
|
||||
# Section used by fun.sh
|
||||
|
||||
[info]
|
||||
# Section used by info.sh
|
||||
DEFAULT_CITY="Toulouse" # Default city for weather forcast
|
||||
|
||||
[lang]
|
||||
# Section used by lang.sh
|
||||
|
||||
[net]
|
||||
# Section used by net.sh
|
||||
|
||||
[packages]
|
||||
# Section used by packages.sh
|
||||
|
||||
[prompt]
|
||||
# Section used by prompt.sh
|
||||
|
||||
[pwd]
|
||||
# Section used by pwd.sh
|
||||
|
||||
[rain]
|
||||
# Section used by rain.sh
|
||||
|
||||
[ssh]
|
||||
# Section used by ssh.sh
|
||||
|
||||
[updates]
|
||||
# Section used by updates.sh
|
||||
|
||||
[general]
|
||||
# General section allow to set any variable that can be used by the user.
|
||||
# It is also a good place to set freely global variables for personal use.
|
||||
# Set some compiling values
|
||||
CFLAGS="-O2 -pipe -march=native"
|
||||
CXXFLAGS="$CFLAGS"
|
||||
MAKEFLAGS='-j12'
|
||||
PKGSOURCES='/share/src/archives'
|
||||
|
||||
[aliases]
|
||||
ll='ls -laFh --color=auto'
|
||||
la='ls -Ah --color=auto'
|
||||
l='ls -CF --color=auto'
|
||||
ls='ls --color=auto'
|
||||
|
||||
grep='grep --color=auto'
|
||||
egrep='egrep --color=auto'
|
||||
fgrep='fgrep --color=auto'
|
||||
qfind="find . -name "
|
||||
|
||||
mkck='make check'
|
||||
mkin='make install'
|
||||
mkdin='make DESTDIR=$PWD/dest-install install'
|
||||
ssh='ssh -Y'
|
||||
|
||||
wget='wget -c' # resume mode by default
|
||||
myip='curl ip.appspot.com'
|
||||
|
||||
# Human readable by default
|
||||
df='df -H'
|
||||
du='du -ch'
|
||||
sdu='du -sk ./* | sort -n'
|
||||
hdu='du -hs ./* | sort -H'
|
||||
@@ -1,123 +1,400 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Smartly uncompress archives (zip only)
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Smartly uncompress archives
|
||||
# Usage: utaz [option] [directorie(s)|file(s)]
|
||||
# Options:
|
||||
# -h, --help Display that help screen
|
||||
# -d, --delete If decompression succeeded, delete the source file
|
||||
# -c, --create-dir Always create a host directory
|
||||
# -n, --no-dir Never create a host directory
|
||||
utaz()
|
||||
{
|
||||
for opt in $@ ; do
|
||||
case $opt in
|
||||
"-h"|"--help")
|
||||
echo "utaz: uncompress all the given files and/or the ones found in the given"
|
||||
echo " directories creating an host directory where needed."
|
||||
echo
|
||||
echo "Usage: utaz [option] [directorie(s)|file(s)]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -h, --help Display that help screen"
|
||||
echo " -d, --delete If decompression succeeded, delete the source file"
|
||||
echo " -c, --create-dir Always create a host directory"
|
||||
echo " -n, --no-dir Never create a host directory"
|
||||
echo
|
||||
return 0
|
||||
;;
|
||||
_ununzip()
|
||||
{
|
||||
unzip -o "$1" -d "$2" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
"-d"|"--delete")
|
||||
local willrm=1
|
||||
;;
|
||||
_untar()
|
||||
{
|
||||
tar -xf "$1" -C "$2"
|
||||
}
|
||||
|
||||
"-c"|"--create-dir")
|
||||
local createdir=1
|
||||
;;
|
||||
_ungzip()
|
||||
{
|
||||
tar -xzf "$1" -C "$2"
|
||||
}
|
||||
|
||||
"-n"|"--no-dir")
|
||||
local nodir=1
|
||||
;;
|
||||
_unbzip2()
|
||||
{
|
||||
tar -xjf "$1" -C "$2"
|
||||
}
|
||||
|
||||
"-"*)
|
||||
echo "Invalid option, use \"utaz --help\" to display options list"
|
||||
echo
|
||||
return 1
|
||||
;;
|
||||
_unxz()
|
||||
{
|
||||
tar -xJf "$1" -C "$2"
|
||||
}
|
||||
|
||||
*)
|
||||
# The ${opt%/} writing is to remove trailing / if any
|
||||
local LIST="$LIST ${opt%/}"
|
||||
;;
|
||||
_unlzop()
|
||||
{
|
||||
lzop -d "$1" -o "$2/$(basename "${1%.*}")"
|
||||
}
|
||||
|
||||
_unlzip()
|
||||
{
|
||||
if command -v plzip >/dev/null 2>&1; then
|
||||
plzip -d -c "$1" > "$2/$(basename "${1%.*}")"
|
||||
else
|
||||
lzip -d -c "$1" > "$2/$(basename "${1%.*}")"
|
||||
fi
|
||||
}
|
||||
|
||||
_ununrar()
|
||||
{
|
||||
unrar x -o+ "$1" "$2/" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_ununarj()
|
||||
{
|
||||
unarj e "$1" "$2/" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_unlza()
|
||||
{
|
||||
# lha typically extracts into the current directory
|
||||
# We ensure it hits the target directory
|
||||
(cd "$2" && lha -x "../$1") >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_ununace()
|
||||
{
|
||||
unace x "$1" "$2/" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_un7z()
|
||||
{
|
||||
7z x "$1" -o"$2/" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_unzstd()
|
||||
{
|
||||
# Zstd decompresses files directly, often requiring tar for archives
|
||||
tar --zstd -xf "$1" -C "$2"
|
||||
}
|
||||
|
||||
_uncpio()
|
||||
{
|
||||
# CPIO requires careful directory handling
|
||||
(cd "$2" && cpio -id < "../$1") >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_uncabextract()
|
||||
{
|
||||
# Requires 'cabextract' package
|
||||
cabextract "$1" -d "$2/" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_undeb()
|
||||
{
|
||||
# Extracts data content from a Debian package
|
||||
dpkg-deb -x "$1" "$2/" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_unrpm()
|
||||
{
|
||||
# Extracts CPIO-based payload from an RPM package
|
||||
# Needs rpm2cpio and cpio
|
||||
rpm2cpio "$1" | (cd "$2/" && cpio -idmv) >/dev/null 2>&1
|
||||
}
|
||||
|
||||
local PARSED=$(getopt -o hdcn --long help,delete,create-dir,no-dir -n 'utaz' -- "$@")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
disp E "Invalid options, use \"utaz --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "utaz: uncompress all the given files and/or the ones found in the given\n"
|
||||
printf " directories creating an host directory where needed.\n\n"
|
||||
printf "Usage: utaz [option] [directorie(s)|file(s)]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay that help screen\n"
|
||||
printf "\t-d, --delete\t\tIf decompression succeeded, delete the source file\n"
|
||||
printf "\t-c, --create-dir\tAlways create a host directory\n"
|
||||
printf "\t-n, --no-dir\t\tNever create a host directory\n\n"
|
||||
printf "Supported archive format:\n"
|
||||
printf "\t- zip\n"
|
||||
printf "\t- tar.gz, .tgz\n"
|
||||
printf "\t- tar.bz2, .tbz2\n"
|
||||
printf "\t- tar.xz, .txz\n"
|
||||
printf "\t- tar.lz, .tlz\n"
|
||||
printf "\t- rar\n"
|
||||
printf "\t- arj\n"
|
||||
printf "\t- lha, lzh\n"
|
||||
printf "\t- ace\n"
|
||||
printf "\t- 7z, p7z\n"
|
||||
printf "\t- zst\n"
|
||||
printf "\t- cpio\n"
|
||||
printf "\t- cab\n"
|
||||
printf "\t- deb\n"
|
||||
printf "\t- rpm\n"
|
||||
return 0
|
||||
;;
|
||||
-d|--delete)
|
||||
local willrm=1
|
||||
shift
|
||||
;;
|
||||
-c|--create-dir)
|
||||
local createdir=1
|
||||
shift
|
||||
;;
|
||||
-n|--no-dir)
|
||||
local nodir=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid option, use \"utaz --help\" to display options list"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# The remaining arguments after -- are the files/directories to process,
|
||||
# "." is used if none is given
|
||||
local FILES=("$@")
|
||||
[[ ${#FILES[@]} -eq 0 ]] && FILES=(".")
|
||||
|
||||
[[ $createdir && $nodir ]] && echo "*** Error: --create-dir and --no-dir options are mutually exclusive."
|
||||
[[ -n ${createdir} && -n ${nodir} ]] && \
|
||||
disp E "The --create-dir and --no-dir options are mutually exclusive."
|
||||
|
||||
[[ ! $LIST ]] && local LIST="."
|
||||
|
||||
for zitem in $LIST; do
|
||||
[[ $(ls $zitem/*.zip 2> /dev/null | wc -l) -eq 0 ]] &&
|
||||
echo "$zitem contains no supported archive file, skipping." &&
|
||||
for zitem in "${FILES[@]}"; do
|
||||
# Build list of input files to process, with whitespace-safe handling.
|
||||
local targets=()
|
||||
if [[ -f "$zitem" ]]; then
|
||||
targets=("$zitem")
|
||||
elif [[ -d "$zitem" ]]; then
|
||||
mapfile -d '' -t targets < <(find "$zitem" -mindepth 1 -maxdepth 1 -print0 2>/dev/null)
|
||||
if [[ ${#targets[@]} -eq 0 ]]; then
|
||||
disp I "Directory ${zitem} is empty, skipping."
|
||||
continue
|
||||
fi
|
||||
else
|
||||
disp W "Path ${zitem} is not a file or directory, skipping."
|
||||
continue
|
||||
fi
|
||||
|
||||
for f in $zitem/*.zip; do
|
||||
echo -n "Processing archive $zitem/$f... "
|
||||
local dir=${f::-4}
|
||||
|
||||
mkdir -p $dir
|
||||
[[ $? -gt 0 ]] &&
|
||||
echo "[ filesystem can't create directories, exit ]" &&
|
||||
return 1
|
||||
|
||||
unzip -o $f -d $dir > /dev/null 2>&1
|
||||
case $? in
|
||||
0)
|
||||
[[ $willrm ]] && rm -f $f && echo -n "Deleted ! "
|
||||
for f in "${targets[@]}"; do
|
||||
local dir="${f%.*}"
|
||||
local extractor=""
|
||||
case "$f" in
|
||||
*.zip)
|
||||
extractor="_ununzip"
|
||||
;;
|
||||
*.tar.gz|*.tgz)
|
||||
extractor="_ungzip"
|
||||
;;
|
||||
|
||||
1)
|
||||
echo "No deletion on warnings "
|
||||
*.tar.bz2|*.tbz2)
|
||||
extractor="_unbzip2"
|
||||
;;
|
||||
*.tar.xz|*.txz)
|
||||
extractor="_unxz"
|
||||
;;
|
||||
*.tar.lz|*.tlz)
|
||||
extractor="_unlzop"
|
||||
;;
|
||||
*.tar)
|
||||
extractor="_untar"
|
||||
;;
|
||||
*.rar)
|
||||
extractor="_ununrar"
|
||||
;;
|
||||
*.arj)
|
||||
extractor="_ununarj"
|
||||
;;
|
||||
*.lzh|*.lha)
|
||||
extractor="_unlha"
|
||||
;;
|
||||
*.ace)
|
||||
extractor="_ununace"
|
||||
;;
|
||||
*.7z|*.p7z)
|
||||
extractor="_un7z"
|
||||
;;
|
||||
*.zst)
|
||||
extractor="_unzstd"
|
||||
;;
|
||||
*.cpio)
|
||||
extractor="_uncpio"
|
||||
;;
|
||||
*.cab)
|
||||
extractor="_uncabextract"
|
||||
;;
|
||||
*.deb)
|
||||
extractor="_undeb"
|
||||
;;
|
||||
*.rpm)
|
||||
extractor="_unrpm"
|
||||
;;
|
||||
*)
|
||||
echo "[ zip file corrupted, failed ]"
|
||||
rm -rf $dir > /dev/null 2>&1
|
||||
disp I "File ${f} is not a supported archive, skipping."
|
||||
continue
|
||||
;;
|
||||
;; # Skip non-archive files
|
||||
esac
|
||||
|
||||
if [[ $createdir ]]; then
|
||||
echo -n "[ subdir created, "
|
||||
elif [[ $nodir ]]; then
|
||||
mv ./$dir/* ./ && rmdir $dir
|
||||
echo -n "[ No subdir, "
|
||||
# Verify binary existence
|
||||
local cmd=${extractor//_un/}
|
||||
if [[ $cmd == "deb" ]]; then
|
||||
command -v -- dpkg-deb >/dev/null 2>&1 || {
|
||||
disp E "The program 'dpkg-deb' is not installed, aborting."
|
||||
continue
|
||||
}
|
||||
elif [[ $cmd == "rpm" ]]; then
|
||||
command -v -- rpm2cpio >/dev/null 2>&1 || {
|
||||
disp E "The program 'rpm2cpio' is not installed, aborting."
|
||||
continue
|
||||
}
|
||||
command -v -- cpio >/dev/null 2>&1 || {
|
||||
disp E "The program 'cpio' is not installed, aborting."
|
||||
continue
|
||||
}
|
||||
else
|
||||
subdirs=$(find $dir -maxdepth 1 | wc -l)
|
||||
if [[ $subdirs -eq 2 ]]; then
|
||||
mv ./$dir/* ./ && rmdir $dir
|
||||
echo -n "[ No subdir, "
|
||||
else
|
||||
echo -n "[ subdir created, "
|
||||
fi
|
||||
command -v -- "${cmd}" >/dev/null 2>&1 || {
|
||||
disp E "Binary ${cmd} necessary to extract ${f} is missing."
|
||||
continue
|
||||
}
|
||||
fi
|
||||
|
||||
disp I "Processing archive ${f} with ${extractor}..."
|
||||
mkdir -p "${dir}"
|
||||
[[ $? -gt 0 ]] &&
|
||||
disp E "The filesystem can't create directories, exit!" &&
|
||||
return 1
|
||||
|
||||
${extractor} "${f}" "${dir}"
|
||||
case $? in
|
||||
0)
|
||||
[[ -n ${willrm} ]] &&
|
||||
rm -f "${f}" && disp I "File ${zitem}/${f} deleted."
|
||||
;;
|
||||
1)
|
||||
if [[ -n ${willrm} ]]; then
|
||||
disp W "Compression program returned a warning: deletion canceled."
|
||||
else
|
||||
disp W "Compression program returned a warning."
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
disp E "The compressed file ${f} seems corrupted, failed."
|
||||
rm -rf "${dir}" >/dev/null 2>&1
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -n ${createdir} ]]; then
|
||||
disp I "Archive extracted successfully in subdirectory."
|
||||
elif [[ -n ${nodir} ]]; then
|
||||
shopt -s nullglob
|
||||
for child in "${dir}"/*; do
|
||||
mv -- "$child" .
|
||||
done
|
||||
shopt -u nullglob
|
||||
rmdir -- "${dir}"
|
||||
disp I "Archive extracted successfully, no subdirectory needed."
|
||||
else
|
||||
# Set nullglob to ensure the array is empty if no files match
|
||||
shopt -s nullglob
|
||||
local contents=( "${dir}"/* )
|
||||
|
||||
# Check if exactly one item exists and if that item is a directory
|
||||
if [[ ${#contents[@]} -eq 1 ]] && [[ -d "${contents[0]}" ]]; then
|
||||
# Single directory detected
|
||||
shopt -s nullglob
|
||||
for child in "${contents[0]}"/*; do
|
||||
mv -- "$child" .
|
||||
done
|
||||
shopt -u nullglob
|
||||
rmdir -- "${dir}"
|
||||
disp I "Archive extracted successfully, no subdirectory needed."
|
||||
else
|
||||
disp I "Archive extracted successfully in subdirectory."
|
||||
fi
|
||||
shopt -u nullglob
|
||||
fi
|
||||
echo " OK ]"
|
||||
done
|
||||
done
|
||||
}
|
||||
export -f utaz
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Compress directories or files into one or more archive
|
||||
# ------------------------------------------------------------------------------
|
||||
taz ()
|
||||
# Usage: taz [option] [--parallel=<n>] [--format=<format>] [directory1 ... directoryN]
|
||||
# Options:
|
||||
# -h, --help Display that help screen
|
||||
# -d, --delete Delete source file or directory after success
|
||||
# -f, --format Chose archive format in the given list. If several format are
|
||||
# given, the smalest is kept
|
||||
# -p, --parallel Number of threads to use (if allowed by underlying utility)
|
||||
# -v, --verbose Display progress where possible
|
||||
# -q, --quiet Display less messages (only errors and warnings)
|
||||
# -1, .., -9 Compression level to use [1=fast/biggest, 9=slow/smallest]
|
||||
taz()
|
||||
{
|
||||
_doxz()
|
||||
{
|
||||
command -v xz >/dev/null 2>&1 || {
|
||||
echo -e >&2 "\t*** The program 'xz' is not installed, aborting."
|
||||
disp E "The program 'xz' is not installed, aborting."
|
||||
return 127
|
||||
}
|
||||
|
||||
[[ $4 ]] && local verb='-v'
|
||||
|
||||
# Display a warning for this format
|
||||
echo -e "\t! Warning: xz format is not suited for long term archiving."
|
||||
echo -e "\t See https://www.nongnu.org/lzip/xz_inadequate.html for details."
|
||||
disp W "xz format is not suited for long term archiving."
|
||||
disp I "See https://www.nongnu.org/lzip/xz_inadequate.html for details."
|
||||
|
||||
# Compresse to xz (lzma2) - Deprecated
|
||||
# Compresse to xz (lzma2) - Deprecated
|
||||
xz $verb --compress --keep -$3 -T $2 $1
|
||||
return $?
|
||||
}
|
||||
@@ -129,14 +406,14 @@ taz ()
|
||||
|
||||
command -v plzip >/dev/null 2>&1 || {
|
||||
command -v lzip >/dev/null 2>&1 || {
|
||||
echo -e >&2 "\t*** Program 'plzip' or 'lzip' are not installed, aborting."
|
||||
disp E "Program 'plzip' or 'lzip' are not installed, aborting."
|
||||
return 127
|
||||
}
|
||||
local command=lzip
|
||||
command=lzip
|
||||
local procopt=""
|
||||
[[ $2 -gt 1 ]] &&
|
||||
echo -e "\t! Warning: lzip doesn't support multithreading, falling back to 1 thread." &&
|
||||
echo -e "\t* Consitder installing plzip to obtain multithreading abilities."
|
||||
disp W "lzip doesn't support multithreading, falling back to 1 thread." &&
|
||||
disp W "Consider installing plzip to obtain multithreading abilities."
|
||||
}
|
||||
|
||||
[[ $4 ]] && local verb="-vv"
|
||||
@@ -153,14 +430,14 @@ taz ()
|
||||
|
||||
command -v pigz >/dev/null 2>&1 || {
|
||||
command -v gzip >/dev/null 2>&1 || {
|
||||
echo -e >&2 "\t*** Programs 'pigz' or 'gzip' are not installed, aborting."
|
||||
disp E "Programs 'pigz' or 'gzip' are not installed, aborting."
|
||||
return 127
|
||||
}
|
||||
local command="gzip --compress"
|
||||
local procopt=""
|
||||
[[ $2 -gt 1 ]] &&
|
||||
echo -e "\t! Warning: gzip doesn't support multithreading, falling back to 1 thread." &&
|
||||
echo -e "\t* Consitder installing pigz to obtain multithreading abilities."
|
||||
disp W "gzip doesn't support multithreading, falling back to 1 thread." &&
|
||||
disp W "Consider installing pigz to obtain multithreading abilities."
|
||||
}
|
||||
|
||||
[[ $4 ]] && local verb="--verbose"
|
||||
@@ -177,14 +454,14 @@ taz ()
|
||||
|
||||
command -v pbzip2 >/dev/null 2>&1 || {
|
||||
command -v bzip2 >/dev/null 2>&1 || {
|
||||
echo -e >&2 "\t*** The program 'pbzip2' or 'bzip2' are not installed, aborting."
|
||||
disp E "The program 'pbzip2' or 'bzip2' are not installed, aborting."
|
||||
return 127
|
||||
}
|
||||
local command=bzip2
|
||||
local procopt=""
|
||||
[[ $2 -gt 1 ]] &&
|
||||
echo -e "\t! Warning: bzip2 doesn't support multithreading, falling back to 1 thread." &&
|
||||
echo -e "\t* Consitder installing pbzip2 to obtain multithreading abilities."
|
||||
disp W "bzip2 doesn't support multithreading, falling back to 1 thread." &&
|
||||
disp W "Consider installing pbzip2 to obtain multithreading abilities."
|
||||
}
|
||||
|
||||
[[ $4 ]] && local verb="-v"
|
||||
@@ -197,98 +474,117 @@ taz ()
|
||||
_dolzo()
|
||||
{
|
||||
command -v lzop >/dev/null 2>&1 || {
|
||||
echo -e >&2 "\t*** The program 'lzop' is not installed, aborting."
|
||||
disp E "The program 'lzop' is not installed, aborting."
|
||||
return 127
|
||||
}
|
||||
|
||||
[[ $4 ]] && local verb='-v'
|
||||
[[ $2 -gt 1 ]] && echo -e "\t! Warning: lzop doesn't support multithreading, falling back to 1 thread."
|
||||
[[ $2 -gt 1 ]] && disp W "lzop doesn't support multithreading, falling back to 1 thread."
|
||||
|
||||
# Compresse au format lzo
|
||||
lzop --keep -$3 $1
|
||||
return $?
|
||||
}
|
||||
|
||||
for opt in $@ ; do
|
||||
case $opt in
|
||||
"-h"|"--help")
|
||||
echo "taz: archive all files of a directory."
|
||||
echo
|
||||
echo "Usage: taz [option] [--parallel=<n>] [--format=<format>] [directory1 ... directoryN]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -h, --help Display that help screen"
|
||||
echo " -d, --delete Delete source file or directory after success"
|
||||
echo " -f, --format Chose archive format in the given list. If several format are"
|
||||
echo " given, the smalest is kept"
|
||||
echo " -p, --parallel Number of threads to use (if allowed by underlying utility)"
|
||||
echo " -v, --verbose Display progress where possible"
|
||||
echo " -1, .., -9 Compression level to use [1=fast/big, 9=slow/small]"
|
||||
echo
|
||||
echo "Supported archive format:"
|
||||
echo " Param.| programs | Algo. | Description"
|
||||
echo " ------+---------------+-------+----------------------------------------"
|
||||
echo " lz | plzip, lzip | lzma | Safe efficient default format"
|
||||
echo " xz | xz | lzma2 | Unsafe, not for long term"
|
||||
echo " bz2 | pbzip2, bzip2 | bzip2 | Historical but less efficient than lz"
|
||||
echo " gz | pigz, gzip | lz77 | Historical, safe, fast"
|
||||
echo " lzo | lzop | lzo | Very fast but no multithread"
|
||||
echo " tar | tar | tar | No compression"
|
||||
echo
|
||||
return 0
|
||||
;;
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hdf:p:vq123456789 --long help,delete,format:,parallel:,verbose,quiet --name "taz" -- "$@")
|
||||
if [ $? -ne 0 ]; then
|
||||
disp E "Invalid options, use \"taz --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "taz: archive all files of a directory.\n\n"
|
||||
printf "Usage: taz [option] [--parallel=<n>] [--format=<format>] [directory1 ... directoryN]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\tDisplay that help screen\n"
|
||||
printf "\t-d, --delete\tDelete source file or directory after success\n"
|
||||
printf "\t-f, --format\tChose archive format in the given list. If several format are"
|
||||
printf "\t\t\tgiven, the smalest is kept\n"
|
||||
printf "\t-p, --parallel\tNumber of threads to use (if allowed by underlying utility)\n"
|
||||
printf "\t-v, --verbose\tDisplay progress where possible\n"
|
||||
printf "\t-q, --quiet\tDisplay less messages (only errors and warnings)\n"
|
||||
printf "\t-1, .., -9\tCompression level to use [1=fast/biggest, 9=slow/smallest]\n\n"
|
||||
printf "Supported archive format:\n"
|
||||
printf "\tParam.| programs | Algo. | Description\n"
|
||||
printf "\t------+---------------+-------+----------------------------------------\n"
|
||||
printf "\t lz | plzip, lzip | lzma | Safe efficient default format\n"
|
||||
printf "\t xz | xz | lzma2 | Unsafe, not for long term\n"
|
||||
printf "\t bz2 | pbzip2, bzip2 | bzip2 | Historical but less efficient than lz\n"
|
||||
printf "\t gz | pigz, gzip | lz77 | Historical, safe, fast\n"
|
||||
printf "\t lzo | lzop | lzo | Very fast but no multithread\n"
|
||||
printf "\t tar | tar | tar | No compression\n"
|
||||
printf "\n"
|
||||
return 0
|
||||
;;
|
||||
|
||||
"-d"|"--delete")
|
||||
local willrm=1
|
||||
;;
|
||||
-d|--delete)
|
||||
local willrm=1
|
||||
shift
|
||||
;;
|
||||
|
||||
"-f"?*|"--format"?*)
|
||||
local compform=$(echo "$opt" | cut -f 2- -d '=')
|
||||
;;
|
||||
-f|--format)
|
||||
local compform=$2
|
||||
shift 2
|
||||
;;
|
||||
|
||||
"-p"?*|"--parallel"?*)
|
||||
local nproc=$(echo "$opt" | cut -f 2- -d '=')
|
||||
;;
|
||||
-p|--parallel)
|
||||
local nproc=$2
|
||||
shift 2
|
||||
;;
|
||||
|
||||
"-v"|"--verbose")
|
||||
local verbose=1
|
||||
;;
|
||||
-v|--verbose)
|
||||
local verbose=1
|
||||
shift
|
||||
;;
|
||||
|
||||
"-"[1..9])
|
||||
local complevel=$(echo $opt | sed 's/-//')
|
||||
;;
|
||||
-q|--quiet)
|
||||
local quiet=1
|
||||
shift
|
||||
;;
|
||||
|
||||
"-"*)
|
||||
echo "Invalid option, use taz --help to display options list"
|
||||
echo
|
||||
return 1
|
||||
;;
|
||||
|
||||
*)
|
||||
local LIST="$LIST ${opt%/}"
|
||||
;;
|
||||
-[1-9])
|
||||
compression="${1#-}"
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid option, use \"taz --help\" to display options list"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# The remaining arguments after -- are the files/directories to process,
|
||||
# "." is used if none is given
|
||||
local FILES=("$@")
|
||||
[[ ${#FILES[@]} -eq 0 ]] && FILES=(".")
|
||||
|
||||
[[ ! $compform ]] && compform=lz # safe and efficient (unless data are already compressed)
|
||||
[[ ! $nproc ]] && nproc=1
|
||||
[[ ! $complevel ]] && complevel=6
|
||||
[[ $verbose -gt 1 && $quiet -gt 1 ]] &&
|
||||
disp E "The --verbose and --quiet options can't be used together."
|
||||
|
||||
for item in $LIST; do
|
||||
for item in "${FILES[@]}"; do
|
||||
local donetar=0
|
||||
echo "--- Processing $item..."
|
||||
disp I "Processing $item..."
|
||||
|
||||
if [[ -d $item ]]; then
|
||||
echo -ne "\t* Creating $item.tar... "
|
||||
if [[ -d "$item" ]]; then
|
||||
disp I "\t Creating $item.tar... "
|
||||
|
||||
tar -cf $item{.tar,}
|
||||
tar -cf "$item.tar" "$item"
|
||||
if [[ ! $? -eq 0 ]]; then
|
||||
echo "[ failed, skipping ]"
|
||||
disp E "tar file creation failed, skipping to next item."
|
||||
continue
|
||||
fi
|
||||
|
||||
local donetar=1
|
||||
echo "[ OK ]"
|
||||
fi
|
||||
|
||||
local fname=$item
|
||||
@@ -296,29 +592,31 @@ taz ()
|
||||
|
||||
# Skip compression part if tar is asked
|
||||
if [[ $compform != "tar" ]]; then
|
||||
echo -e "\t* Compressing archive..."
|
||||
_do$compform $fname $nproc $complevel $verbose
|
||||
disp I "\t Compressing archive..."
|
||||
_do$compform "$fname" "$nproc" "$complevel" "$verbose"
|
||||
[[ ! $? -eq 0 ]] && case $? in
|
||||
127)
|
||||
echo -e "\t*** Compression program unavailable, aborting."
|
||||
return 127
|
||||
;;
|
||||
*)
|
||||
echo -e "\t*** Compression program returned an error, not deleting anything if asked, skipping to next item."
|
||||
continue
|
||||
;;
|
||||
127)
|
||||
disp E "Compression program unavailable, aborting."
|
||||
return 127
|
||||
;;
|
||||
*)
|
||||
disp E "Compression program returned an error, not deleting anything if asked, skipping to next item."
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
[[ $donetar -gt 0 ]] && rm $fname
|
||||
[[ $donetar -gt 0 ]] && rm "$fname"
|
||||
fi
|
||||
|
||||
if [[ $willrm ]]; then
|
||||
echo -en "\t* Deleting original source as asked... "
|
||||
rm -r $item && echo '[ OK ]' || echo '[ failed ]'
|
||||
disp I "\t Deleting original source as asked... "
|
||||
rm -r "$item"
|
||||
fi
|
||||
|
||||
echo "--- Done"
|
||||
done
|
||||
|
||||
unset quiet
|
||||
}
|
||||
export -f taz
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
@@ -1,72 +1,130 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Display a backtrace
|
||||
# ------------------------------------------------------------------------------
|
||||
function backtrace ()
|
||||
# Usage: backtrace
|
||||
function backtrace()
|
||||
{
|
||||
echo "========= Call stack ========="
|
||||
typeset -i i=0
|
||||
|
||||
local func=
|
||||
for func in "${FUNCNAME[@]}"; do
|
||||
if [[ $i -ne 0 ]]; then
|
||||
printf '%15s() %s:%d\n' \
|
||||
"$func" "${BASH_SOURCE[$i]}" "${BASH_LINENO[ (( $i - 1)) ]}"
|
||||
fi
|
||||
let i++ || true
|
||||
printf "========= Call stack =========\n"
|
||||
local i=1 # We begin at 1 to ignore backtrace itself
|
||||
while [[ $i -lt ${#FUNCNAME[@]} ]]; do
|
||||
printf '%15s() %s:%d\n' \
|
||||
"${FUNCNAME[$i]}" "${BASH_SOURCE[$i]}" "${BASH_LINENO[$(( i-1 ))]}"
|
||||
((i++))
|
||||
done
|
||||
unset func i
|
||||
echo "=============================="
|
||||
unset i
|
||||
printf "==============================\n"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Function to be trapped for errors investigation
|
||||
# ------------------------------------------------------------------------------
|
||||
function error ()
|
||||
function error()
|
||||
{
|
||||
local errcode=$?
|
||||
backtrace
|
||||
return $errcode
|
||||
}
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Activate or deactivate error trapping to display backtrace
|
||||
# ------------------------------------------------------------------------------
|
||||
settrace ()
|
||||
# Usage: settrace <--on|--off|--status>
|
||||
settrace()
|
||||
{
|
||||
local status="off"
|
||||
[[ $(trap -p ERR) ]] && status="on"
|
||||
#trap -p ERR
|
||||
for opt in $@ ; do
|
||||
case $opt in
|
||||
"-h"|"--help")
|
||||
echo "Try to activate backtrace display for script debugging."
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " --on Activate backtrace generation"
|
||||
echo " --off Deactivate backtrace generation"
|
||||
echo
|
||||
echo "That function active a trap event on error. If the script you want to"
|
||||
echo "debug overload the ERR bash trap, it will not work."
|
||||
echo
|
||||
;;
|
||||
"--on")
|
||||
if [[ $status == "on" ]]; then
|
||||
echo "Warning: ERR signal trap is already set, replacing previous trap!"
|
||||
fi
|
||||
trap "error" ERR
|
||||
;;
|
||||
"--off")
|
||||
if [[ $status != "on" ]]; then
|
||||
echo "Warning: ERR signal trap is already unset!"
|
||||
fi
|
||||
trap - ERR
|
||||
;;
|
||||
"--status")
|
||||
echo "ERR trap signal is ${status}."
|
||||
;;
|
||||
esac
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -oh --long help,on,off,status,force -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"settrace --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
local force=0
|
||||
while true; do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
printf "Try to activate backtrace display for script debugging.\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t--on\t\tActivate backtrace generation\n"
|
||||
printf "\t--force\t\tForce replacement of existing trap (use with --on)\n"
|
||||
printf "\t--off\t\tDeactivate backtrace generation\n\n"
|
||||
printf "That function active a trap event on error. If the script you want to\n"
|
||||
printf "debug overload the ERR bash trap, it will not work.\n"
|
||||
return 0
|
||||
;;
|
||||
--on)
|
||||
if [[ ${status} == "on" ]] && [[ $force -eq 0 ]]; then
|
||||
disp E "ERR signal trap is already set. Use --force to replace it."
|
||||
return 1
|
||||
fi
|
||||
trap "error" ERR
|
||||
shift
|
||||
;;
|
||||
--force)
|
||||
force=1
|
||||
shift
|
||||
;;
|
||||
--off)
|
||||
if [[ ${status} != "on" ]]; then
|
||||
disp W "ERR signal trap is already unset!"
|
||||
fi
|
||||
trap - ERR
|
||||
shift
|
||||
;;
|
||||
--status)
|
||||
disp I "Trap signal is ${status}."
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"settrace --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
unset status
|
||||
unset status force
|
||||
}
|
||||
export -f settrace
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
183
profile.d/disp.sh
Normal file
183
profile.d/disp.sh
Normal file
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Color definitions
|
||||
# Standard 16 colors display declaration
|
||||
export DEFAULTFG='\e[0;39m'
|
||||
export DEFAULTBG='\e[0;49m'
|
||||
export DEFAULTCOL="${DEFAULTBG}${DEFAULTFG}"
|
||||
export RESETCOL=$'\e[0m'
|
||||
|
||||
# Regular Colors
|
||||
export Black='\e[0;30m'
|
||||
export Red='\e[0;31m'
|
||||
export Green='\e[0;32m'
|
||||
export Yellow='\e[0;33m'
|
||||
export Blue='\e[0;34m'
|
||||
export Purple='\e[0;35m'
|
||||
export Cyan='\e[0;36m'
|
||||
export White='\e[0;37m'
|
||||
|
||||
# Bold
|
||||
export BBlack='\e[1;30m'
|
||||
export BRed='\e[1;31m'
|
||||
export BGreen='\e[1;32m'
|
||||
export BYellow='\e[1;33m'
|
||||
export BBlue='\e[1;34m'
|
||||
export BPurple='\e[1;35m'
|
||||
export BCyan='\e[1;36m'
|
||||
export BWhite='\e[1;37m'
|
||||
|
||||
# Underline
|
||||
export UBlack='\e[4;30m'
|
||||
export URed='\e[4;31m'
|
||||
export UGreen='\e[4;32m'
|
||||
export UYellow='\e[4;33m'
|
||||
export UBlue='\e[4;34m'
|
||||
export UPurple='\e[4;35m'
|
||||
export UCyan='\e[4;36m'
|
||||
export UWhite='\e[4;37m'
|
||||
|
||||
# Background
|
||||
export On_Black='\e[40m'
|
||||
export On_Red='\e[41m'
|
||||
export On_Green='\e[42m'
|
||||
export On_Yellow='\e[43m'
|
||||
export On_Blue='\e[44m'
|
||||
export On_Purple='\e[45m'
|
||||
export On_Cyan='\e[46m'
|
||||
export On_White='\e[47m'
|
||||
|
||||
# High Intensity
|
||||
export IBlack='\e[0;90m'
|
||||
export IRed='\e[0;91m'
|
||||
export IGreen='\e[0;92m'
|
||||
export IYellow='\e[0;93m'
|
||||
export IBlue='\e[0;94m'
|
||||
export IPurple='\e[0;95m'
|
||||
export ICyan='\e[0;96m'
|
||||
export IWhite='\e[0;97m'
|
||||
|
||||
# Bold High Intensity
|
||||
export BIBlack='\e[1;90m'
|
||||
export BIRed='\e[1;91m'
|
||||
export BIGreen='\e[1;92m'
|
||||
export BIYellow='\e[1;93m'
|
||||
export BIBlue='\e[1;94m'
|
||||
export BIPurple='\e[1;95m'
|
||||
export BICyan='\e[1;96m'
|
||||
export BIWhite='\e[1;97m'
|
||||
|
||||
# High Intensity backgrounds
|
||||
export On_IBlack='\e[0;100m'
|
||||
export On_IRed='\e[0;101m'
|
||||
export On_IGreen='\e[0;102m'
|
||||
export On_IYellow='\e[0;103m'
|
||||
export On_IBlue='\e[0;104m'
|
||||
export On_IPurple='\e[0;105m'
|
||||
export On_ICyan='\e[0;106m'
|
||||
export On_IWhite='\e[0;107m'
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Display a message
|
||||
# Usage: disp <type> <message>
|
||||
# Types:
|
||||
# I : info (green)
|
||||
# W : warning (yellow)
|
||||
# E : error (red)
|
||||
# D : debug (cyan)
|
||||
disp()
|
||||
{
|
||||
# Handle NO_COLOR: disable colors if set
|
||||
local color_enabled=1
|
||||
[[ -n $NO_COLOR ]] && color_enabled=0
|
||||
|
||||
case ${1^^} in
|
||||
"I")
|
||||
if [[ $color_enabled -eq 1 ]]; then
|
||||
local heads="[ ${IGreen}info${DEFAULTFG} ]"
|
||||
else
|
||||
local heads="[ info ]"
|
||||
fi
|
||||
shift
|
||||
[[ -z $QUIET || $QUIET -ne 1 ]] && \
|
||||
printf "%b\n" "${heads} $*${RESETCOL}"
|
||||
;;
|
||||
"W")
|
||||
if [[ $color_enabled -eq 1 ]]; then
|
||||
local heads="[ ${IYellow}Warning${DEFAULTFG} ]"
|
||||
else
|
||||
local heads="[ Warning ]"
|
||||
fi
|
||||
shift
|
||||
printf "%b\n" "${heads} $*${RESETCOL}" >&2
|
||||
;;
|
||||
"E")
|
||||
if [[ $color_enabled -eq 1 ]]; then
|
||||
local heads="[ ${IRed}ERROR${DEFAULTFG} ]"
|
||||
else
|
||||
local heads="[ ERROR ]"
|
||||
fi
|
||||
shift
|
||||
printf "%b\n" "${heads} $*${RESETCOL}" >&2
|
||||
;;
|
||||
"D")
|
||||
if [[ $color_enabled -eq 1 ]]; then
|
||||
local heads="[ ${ICyan}debug${DEFAULTFG} ]"
|
||||
else
|
||||
local heads="[ debug ]"
|
||||
fi
|
||||
shift
|
||||
[[ -n $DEBUG && $DEBUG -gt 1 ]] && \
|
||||
printf "%b\n" "${heads} $*${RESETCOL}"
|
||||
;;
|
||||
* )
|
||||
[[ -z $QUIET || $QUIET -ne 1 ]] && \
|
||||
printf "%b\n" "$*"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
export -f disp
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Load disp section variables
|
||||
load_conf disp
|
||||
|
||||
# EOF
|
||||
@@ -1,73 +1,133 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# expandlist : treat wildcards in a file/directory list
|
||||
# ------------------------------------------------------------------------------
|
||||
# Usage: expandlist <item1 [item2 ... itemN]>
|
||||
expandlist()
|
||||
{
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "expandlist: Wraps a list of items in double quotes.\n\n"
|
||||
printf "Usage: expandlist <item1 [item2 ... itemN]>\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local result=""
|
||||
for item in "$1"; do
|
||||
for item in "$@"; do
|
||||
for content in "$item"; do
|
||||
result+="\"$content\" "
|
||||
done
|
||||
done
|
||||
echo $result
|
||||
}
|
||||
export -f expandlist
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Clean a directory or a tree from temporary or backup files
|
||||
# ------------------------------------------------------------------------------
|
||||
clean ()
|
||||
# Usage: clean [options] [directory1] [...[directoryX]]
|
||||
# Options:
|
||||
# -h, --help: display help screen
|
||||
# -r, --recurs: do a recursive cleaning
|
||||
# -f, --force: do not ask for confirmation (use with care)
|
||||
# -s, --shell: do nothing and display what will be executed
|
||||
clean()
|
||||
{
|
||||
for opt in $@ ; do
|
||||
case $opt in
|
||||
"-r"|"--recurs")
|
||||
local recursive=1
|
||||
;;
|
||||
local recursive=0 force=0 outshell=0
|
||||
|
||||
"-h"|"--help")
|
||||
echo "clean: erase backup files in the given directories."
|
||||
echo
|
||||
echo "Usage: clean [option] [directory1] [...[directoryX]]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -h, --help Display that help screen"
|
||||
echo " -r, --recurs Do a recursive cleaning"
|
||||
echo " -f, --force Do not ask for confirmation (use with care)"
|
||||
echo " -s, --shell Do nothing and display what will be executed"
|
||||
echo
|
||||
# Define short and long options
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hrsf --long help,recurs,shell,force -n 'clean' -- "$@")
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"clean --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-r|--recurs)
|
||||
local recursive=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
printf "clean: erase backup files in the given directories.\n\n"
|
||||
printf "Usage: clean [option] [directory1] [...[directoryX]]\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay that help screen\n"
|
||||
printf "\t-r, --recurs\t\tDo a recursive cleaning\n"
|
||||
printf "\t-f, --force\t\tDo not ask for confirmation (use with care)\n"
|
||||
printf "\t-s, --shell\t\tDo nothing and display what will be executed\n"
|
||||
printf "\n"
|
||||
return 0
|
||||
;;
|
||||
|
||||
"-s"|"--shell")
|
||||
-s|--shell)
|
||||
local outshell=1
|
||||
shift
|
||||
;;
|
||||
|
||||
"-f"|"--force")
|
||||
-f|--force)
|
||||
local force=1
|
||||
shift
|
||||
;;
|
||||
|
||||
"-"*)
|
||||
echo "Invalid option, use \"clean --help\" to display usage."
|
||||
echo
|
||||
return 1
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
|
||||
*)
|
||||
local dirlist="$dirlist $opt"
|
||||
;;
|
||||
disp E "Invalid parameter, use \"clean --help\" to display options list"
|
||||
return 1
|
||||
esac
|
||||
done
|
||||
|
||||
[[ ! $dirlist ]] && local dirlist=$(pwd)
|
||||
# Handle remaining arguments as directories
|
||||
local dirlist=("$@")
|
||||
[[ ${#dirlist[@]} -eq 0 ]] && dirlist=(".")
|
||||
|
||||
[[ ! $recursive ]] && local findopt="-maxdepth 1"
|
||||
[[ ! $force ]] && local rmopt="-i"
|
||||
local findopt=() rmopt
|
||||
[[ ! $recursive ]] && findopt=(-maxdepth 1)
|
||||
[[ ! $force ]] && rmopt="-i"
|
||||
unset recursive force
|
||||
|
||||
for dir in $dirlist; do
|
||||
local dellist=$(find $dir $findopt -type f -name "*~" -o -name "#*#" \
|
||||
-o -name "*.bak" -o -name ".~*#")
|
||||
for f in $dellist; do
|
||||
find "$dir" "${findopt[@]}" -type f \( -name "*~" -o -name "#*#" -o -name "*.bak" -o -name ".~*#" \) -print0 | while IFS= read -r -d '' f; do
|
||||
if [[ ! $outshell ]]; then
|
||||
rm $rmopt $f
|
||||
else
|
||||
@@ -78,71 +138,100 @@ clean ()
|
||||
unset outshell dirlist dellist findopt rmopt
|
||||
}
|
||||
export -f clean
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Create a directory then goes inside
|
||||
# ------------------------------------------------------------------------------
|
||||
mcd ()
|
||||
# Usage: mcd <directory>
|
||||
mcd()
|
||||
{
|
||||
if [[ ! $# -eq 1 ]] ; then
|
||||
echo "Create a directory then goes inside."
|
||||
echo "Usage: mcd <directory>"
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "mcd: Create a directory and enter it.\n\n"
|
||||
printf "Usage: mcd <directory>\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ ! $# -eq 1 ]]; then
|
||||
disp E "Missing parameter. Use \"mcd --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
mkdir -pv $1 && cd $1
|
||||
mkdir -pv "$1" && cd "$1" || {
|
||||
printf "Failed create and/or change directory.\n"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
export -f mcd
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Rename all files in current directory to replace spaces with _
|
||||
# ------------------------------------------------------------------------------
|
||||
rmspc ()
|
||||
# Usage: rmspc [options]
|
||||
# Options:
|
||||
# -h, --help: display help screen
|
||||
# -r, --recursive: treat subdirectories of the given directory
|
||||
# -c, --subst-char: change the replacement character (default is underscore)
|
||||
# -v, --verbose: display more details (recursive mode only)
|
||||
# -s, --shell: do nothing and display commands that would be executed
|
||||
rmspc()
|
||||
{
|
||||
local lst=""
|
||||
for opt in $@ ; do
|
||||
case $opt in
|
||||
"-h"|"--help")
|
||||
echo "rmspc: remove spaces from all filenames in current directories"
|
||||
echo
|
||||
echo "Usage: rmspc [option]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -h, --help Display that help screen"
|
||||
echo " -r, --recursive Treat subdirectories of the given directory"
|
||||
echo " -c, --subst-char Change the replacement character (default is underscore)"
|
||||
echo " -v, --verbose Display what is being done"
|
||||
echo " -s, --shell Do nothing and display commands that would be executed"
|
||||
echo
|
||||
echo "Note: if the --subst-char option is given without parameters, spaces will be"
|
||||
echo " replaced with nothing (concatenation)."
|
||||
echo
|
||||
return 0
|
||||
;;
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hr:c::vs --long help,recursive,subst-char::,verbose,shell -n 'rmspc' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"rmspc --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
"-r"|"--recursive")
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "rmspc: remove spaces from all filenames in current directories\n\n"
|
||||
printf "Usage: rmspc [option]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay that help screen\n"
|
||||
printf "\t-r, --recursive\t\tTreat subdirectories of the given directory\n"
|
||||
printf "\t-c, --subst-char\tChange the replacement character (default is underscore)\n"
|
||||
printf "\t-v, --verbose\t\tDisplay more details (recursive mode only)\n"
|
||||
printf "\t-s, --shell\t\tDo nothing and display commands that would be executed\n\n"
|
||||
printf "Note: if the --subst-char option is given without parameters, spaces will be\n"
|
||||
printf " replaced with nothing (concatenation).\n"
|
||||
return 0
|
||||
;;
|
||||
-r|--recursive)
|
||||
local recurs=1
|
||||
shift
|
||||
;;
|
||||
|
||||
"-c"?*|"--subst-char"?*)
|
||||
if [[ $(echo $opt | grep "=") ]]; then
|
||||
local substchar=$(echo "$opt" | cut -f 2- -d '=')
|
||||
else
|
||||
local substchar='none'
|
||||
fi
|
||||
;;
|
||||
|
||||
"-v"|"--verbose")
|
||||
local verb=1
|
||||
-c|--subst-char)
|
||||
# Handle optional argument for short/long options
|
||||
case "$2" in
|
||||
"")
|
||||
substchar=""
|
||||
;;
|
||||
*)
|
||||
substchar="$2"
|
||||
;;
|
||||
esac
|
||||
shift 2
|
||||
;;
|
||||
|
||||
"-s"|"--shell")
|
||||
-v|--verbose)
|
||||
local verb=1
|
||||
shift
|
||||
;;
|
||||
-s|--shell)
|
||||
local shell=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Invalid parameter, use \"rmspc --help\" to display options list"
|
||||
disp E "Invalid parameter, use \"rmspc --help\" to display options list"
|
||||
echo
|
||||
return 1
|
||||
;;
|
||||
@@ -153,27 +242,485 @@ rmspc ()
|
||||
[[ $substchar == "none" ]] && local substchar=""
|
||||
[[ $verb ]] && local mvopt="-v"
|
||||
|
||||
shopt -s nullglob
|
||||
for f in *; do
|
||||
[[ $recurs ]] && [[ -d "$f" ]] && (
|
||||
[[ $verb ]] && echo "-- Entering directory $(pwd)/$f ..."
|
||||
local lastdir=$f
|
||||
pushd "$f" > /dev/null
|
||||
rmspc $@
|
||||
popd > /dev/null
|
||||
[[ $verb ]] && echo "-- Leaving directory $(pwd)/$lastdir"
|
||||
unset lastdir
|
||||
[[ $verb ]] && disp I "Entering directory $(pwd)/$f ..."
|
||||
local lastdir=$f
|
||||
pushd "$f" >/dev/null
|
||||
rmspc ${recurs:+-r} ${substchar:+-c "$substchar"} ${verb:+-v} ${shell:+-s}
|
||||
popd >/dev/null
|
||||
[[ $verb ]] && disp I "Leaving directory $(pwd)/$lastdir"
|
||||
unset lastdir
|
||||
)
|
||||
|
||||
if [[ $(echo $f | grep " ") ]]; then
|
||||
|
||||
if [[ "$f" == *" "* ]]; then
|
||||
local newf="${f// /${substchar}}"
|
||||
local command="mv $mvopt \"$f\" \"$newf\""
|
||||
if [[ $shell ]]; then
|
||||
echo $command
|
||||
[[ "$f" == "$newf" ]] && continue # protection but should never happen
|
||||
if [[ -n $shell ]]; then
|
||||
echo "mv ${mvopt:+$mvopt }\"$f\" \"$newf\""
|
||||
else
|
||||
$command
|
||||
mv ${mvopt:+$mvopt} "$f" "$newf" || {
|
||||
disp E "Failed renaming \"$f\" to \"$newf\"."
|
||||
continue
|
||||
}
|
||||
fi
|
||||
fi
|
||||
done
|
||||
unset lst substchar verb shell newf command mvopt
|
||||
unset lst substchar verb shell newf command mvopt
|
||||
}
|
||||
export -f rmspc
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# display stats about a file structure
|
||||
# Usage: file_stats [options] [path]
|
||||
# Options:
|
||||
# -H, --human Human readable sizes\n"
|
||||
# -d, --details Display details (min/max/average/median)
|
||||
# -m, --average Display only average size
|
||||
# -M, --median Display only median size
|
||||
# -c, --count Display only count of files
|
||||
# -t, --total Display only total size
|
||||
# -a, --all Display all stats in human readable format (shortcut for -H -d)
|
||||
# -x, --ext [ext] Filter by extension (e.g. -x log for .log files)
|
||||
# -X, --ext-list [list] Filter by multiple extensions (e.g. -X log,txt)
|
||||
# --min [size] Minimum size (e.g., 10M)
|
||||
# --max [size] Maximum size (e.g., 100M)
|
||||
file_stats()
|
||||
{
|
||||
local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0
|
||||
local path="." show_all=1 ext_filter="" ext_list="" min_size="" max_size=""
|
||||
|
||||
local PARSED
|
||||
# Short: H, d, m, M, c, t, a, x:, X:
|
||||
# Long: human, details, average, median, count, total, all, ext:, ext-list:, min:, max:, help
|
||||
PARSED=$(getopt -o HdmMctax:X:h --long human,details,average,median,count,total,all,ext:,ext-list:,min:,max:,help -n 'file_stats' -- "$@")
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"file_stats --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "Usage: file_stats [options] [path]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-H, --human\t\tHuman readable sizes\n"
|
||||
printf "\t-d, --details\t\tShow detailed histogram\n"
|
||||
printf "\t-m, --average\t\tShow only average size\n"
|
||||
printf "\t-M, --median\t\tShow only median size\n"
|
||||
printf "\t-c, --count\t\tShow only file count\n"
|
||||
printf "\t-t, --total\t\tShow only total size\n"
|
||||
printf "\t-a, --all\t\tShow all (human + details)\n"
|
||||
printf "\t-x, --ext [ext]\t\tFilter by extension\n"
|
||||
printf "\t-X, --ext-list [list]\tFilter by comma-separated list\n"
|
||||
printf "\t--min [size]\t\tMinimum size (e.g., 10M)\n"
|
||||
printf "\t--max [size]\t\tMaximum size (e.g., 100M)\n"
|
||||
return 0 ;;
|
||||
-H|--human)
|
||||
human=1
|
||||
shift
|
||||
;;
|
||||
-d|--details)
|
||||
details=1
|
||||
shift
|
||||
;;
|
||||
-m|--average)
|
||||
only_avg=1
|
||||
show_all=0
|
||||
shift
|
||||
;;
|
||||
-M|--median)
|
||||
only_med=1
|
||||
show_all=0
|
||||
shift
|
||||
;;
|
||||
-c|--count)
|
||||
only_count=1
|
||||
show_all=0
|
||||
shift
|
||||
;;
|
||||
-t|--total)
|
||||
only_total=1
|
||||
show_all=0
|
||||
shift
|
||||
;;
|
||||
-a|--all)
|
||||
human=1
|
||||
details=1
|
||||
shift
|
||||
;;
|
||||
-x|--ext)
|
||||
ext_filter="${2#.}"
|
||||
shift 2
|
||||
;;
|
||||
-X|--ext-list)
|
||||
ext_list="$2"
|
||||
shift 2
|
||||
;;
|
||||
--min)
|
||||
min_size="$2"
|
||||
shift 2
|
||||
;;
|
||||
--max)
|
||||
max_size="$2"
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid option: $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
[[ -n "$1" ]] && path="$1"
|
||||
|
||||
# Prepare find filters
|
||||
local find_cmd=(find "$path" -type f)
|
||||
|
||||
# Extension simple
|
||||
if [[ -n "$ext_filter" ]]; then
|
||||
find_cmd+=(-iname "*.$ext_filter")
|
||||
fi
|
||||
|
||||
# Extension liste
|
||||
if [[ -n "$ext_list" ]]; then
|
||||
IFS=',' read -ra exts <<< "$ext_list"
|
||||
find_cmd+=('(')
|
||||
for i in "${!exts[@]}"; do
|
||||
[[ $i -ne 0 ]] && find_cmd+=(-o)
|
||||
find_cmd+=(-iname "*.${exts[$i]}")
|
||||
done
|
||||
find_cmd+=(')')
|
||||
fi
|
||||
|
||||
# Taille min/max (à évaluer en octets)
|
||||
if [[ -n "$min_size" ]]; then
|
||||
find_cmd+=(-size +"$(numfmt --from=iec "$min_size")"c)
|
||||
fi
|
||||
if [[ -n "$max_size" ]]; then
|
||||
find_cmd+=(-size -"$(( $(numfmt --from=iec "$max_size") + 1 ))"c)
|
||||
fi
|
||||
|
||||
# Exécution
|
||||
"${find_cmd[@]}" -printf "%s\n" 2>/dev/null | sort -n | \
|
||||
awk -v human="$human" -v details="$details" -v only_avg="$only_avg" \
|
||||
-v only_med="$only_med" -v only_count="$only_count" \
|
||||
-v only_total="$only_total" -v show_all="$show_all" -v path="$path" '
|
||||
# Convert function
|
||||
function human_readable(x) {
|
||||
split("B KiB MiB GiB TiB", units)
|
||||
i = 1
|
||||
while (x >= 1024 && i < 5) {
|
||||
x /= 1024
|
||||
i++
|
||||
}
|
||||
return sprintf("%.2f %s", x, units[i])
|
||||
}
|
||||
|
||||
# Display function
|
||||
function out(label, val, is_size) {
|
||||
if (human == 1 && is_size == 1) val = human_readable(val)
|
||||
printf "%-20s : %s\n", label, val
|
||||
}
|
||||
|
||||
{
|
||||
sizes[NR] = $1
|
||||
total += $1
|
||||
if (min == "" || $1 < min) min = $1
|
||||
if (max == "" || $1 > max) max = $1
|
||||
if ($1 == 0) bucket[0]++
|
||||
else {
|
||||
b = int(log($1)/log(1024))
|
||||
bucket[b]++
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
count = NR
|
||||
if (count == 0) {
|
||||
print "No files found."
|
||||
exit
|
||||
}
|
||||
|
||||
average = total / count
|
||||
|
||||
# Median calculation: exact using sorted array values
|
||||
if (count % 2 == 1) {
|
||||
median = sizes[(count + 1) / 2]
|
||||
} else {
|
||||
idx = count / 2
|
||||
median = (sizes[idx] + sizes[idx + 1]) / 2
|
||||
}
|
||||
|
||||
if (only_avg) out("Average size", average, 1)
|
||||
else if (only_med) out("Median size", median, 1)
|
||||
else if (only_count) out("Number of files", count, 0)
|
||||
else if (only_total) out("Total size", total, 1)
|
||||
else {
|
||||
if (show_all || human || details) {
|
||||
printf "Statistics for \"%s\"\n", path
|
||||
printf "-------------------------\n"
|
||||
}
|
||||
out("Number of files", count, 0)
|
||||
out("Total size", total, 1)
|
||||
out("Average size", average, 1)
|
||||
out("Median size", median, 1)
|
||||
out("Minimum size", min, 1)
|
||||
out("Maximum size", max, 1)
|
||||
}
|
||||
if (details) {
|
||||
print "\nSize histogram:"
|
||||
|
||||
# Use a separate array for the loop to avoid collision
|
||||
for (b in bucket) {
|
||||
# Pre-calculate label parts
|
||||
# 1024^0 = 1 (B), 1024^1 = 1K, etc.
|
||||
low = (b == 0) ? 0 : (1024^b)
|
||||
high = 1024^(b+1)
|
||||
|
||||
label = sprintf("%-9s – %-9s",
|
||||
(b == 0) ? "0" : human_readable(low),
|
||||
human_readable(high))
|
||||
|
||||
# We store buckets in an array, access them by index b
|
||||
printf "%-25s : %6d fichiers\n", label, bucket[b]
|
||||
}
|
||||
}
|
||||
}'
|
||||
}
|
||||
export -f file_stats
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Find the biggest files in a directory tree
|
||||
# Usage: findbig [options] [directory]
|
||||
# Options:
|
||||
# -h : display help screen
|
||||
# -d : display details (ls -l) for each file
|
||||
# -x : do not cross filesystem boundaries
|
||||
# -l : limit : number of files to return (default is 10)
|
||||
findbig()
|
||||
{
|
||||
local details=0 limit=10 no_change=0 one_fs=0
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hd:l:x --long help,details,one-fs,limit: -n 'findbig' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"findbig --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "findbig: Find the N biggest files in a directory tree.\n\n"
|
||||
printf "Usage: findbig [options] [directory]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "\t-d, --details\t\tShow detailed file info (ls -ld)\n"
|
||||
printf "\t-l, --limit N\t\tNumber of files to return (default: 10)\n"
|
||||
printf "\t-x, --one-fs\t\tDo not cross filesystem boundaries\n"
|
||||
return 0
|
||||
;;
|
||||
-d|--details)
|
||||
details=1
|
||||
shift
|
||||
;;
|
||||
-n|--no-change)
|
||||
no_change=1
|
||||
shift
|
||||
;;
|
||||
-l|--limit)
|
||||
limit="$2"
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid option: $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local dir="${1:-.}"
|
||||
|
||||
# Prepare find arguments in an array for cleaner handling
|
||||
local find_args=("-L" "$dir" "-type" "f")
|
||||
(( one_fs )) && find_args+=("-xdev")
|
||||
|
||||
# Logic: find files, print size and path, sort numeric reverse, take N
|
||||
if (( details )); then
|
||||
find "${find_args[@]}" -printf "%s %p\n" 2>/dev/null | sort -rn | head -n "$limit" | while read -r size path; do
|
||||
ls -ld "$path"
|
||||
done
|
||||
else
|
||||
find "${find_args[@]}" -printf "%s %p\n" 2>/dev/null | sort -rn | head -n "$limit"
|
||||
fi
|
||||
}
|
||||
export -f findbig
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Find empty files in a directory tree
|
||||
# Usage: findzero [options] [directory]
|
||||
# Options:
|
||||
# -h : display help screen
|
||||
# -d : display details (ls -l) for each file
|
||||
# -x : do not cross filesystem boundaries
|
||||
# --delete : delete empty files and display their paths
|
||||
findzero()
|
||||
{
|
||||
local delete=0 details=0 one_fs=0 no_change=0
|
||||
|
||||
local PARSED
|
||||
# o: options, long: long equivalents
|
||||
PARSED=$(getopt -o hdx --long help,details,one-fs,delete -n 'findzero' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"findzero --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "findzero: Find or delete empty files in a directory tree.\n\n"
|
||||
printf "Usage: findzero [options] [directory]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "\t-d, --details\t\tShow detailed file info (ls -ls)\n"
|
||||
printf "\t-x, --one-fs\t\tDo not cross filesystem boundaries\n"
|
||||
printf "\t--delete\t\tActually remove the empty files\n"
|
||||
return 0 ;;
|
||||
-d|--details)
|
||||
details=1
|
||||
shift
|
||||
;;
|
||||
-x|--one-fs)
|
||||
one_fs=1
|
||||
shift
|
||||
;;
|
||||
--delete)
|
||||
delete=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid option: $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local dir="${1:-.}"
|
||||
local find_args=("-L" "$dir" "-type" "f" "-empty")
|
||||
|
||||
(( one_fs )) && find_args+=("-xdev")
|
||||
|
||||
# Execution logic
|
||||
if (( delete )); then
|
||||
disp W "Deleting empty files in $dir..."
|
||||
find "${find_args[@]}" -delete -print
|
||||
elif (( details )); then
|
||||
find "${find_args[@]}" -ls
|
||||
else
|
||||
find "${find_args[@]}"
|
||||
fi
|
||||
}
|
||||
export -f findzero
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Find dead symbolic links in a directory tree
|
||||
# Usage: finddead [options] [directory]
|
||||
# Options:
|
||||
# -h : display help screen
|
||||
# -d : display details (ls -l) for each link
|
||||
# -x : do not cross filesystem boundaries
|
||||
# --delete : delete dead links and display their paths
|
||||
finddead()
|
||||
{
|
||||
local delete=0 details=0 one_fs=0 no_change=0
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hdx --long help,details,one-fs,delete -n 'finddead' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"finddead --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "finddead: Find or delete dead/broken symbolic links.\n\n"
|
||||
printf "Usage: finddead [options] [directory]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "\t-d, --details\t\tShow detailed symlink info (ls -ls)\n"
|
||||
printf "\t-x, --one-fs\t\tDo not cross filesystem boundaries\n"
|
||||
printf "\t--delete\t\tActually remove the dead links\n"
|
||||
return 0 ;;
|
||||
-d|--details)
|
||||
details=1
|
||||
shift
|
||||
;;
|
||||
-x|--one-fs)
|
||||
one_fs=1
|
||||
shift
|
||||
;;
|
||||
--delete)
|
||||
delete=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid option: $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local dir="${1:-.}"
|
||||
# -xtype l searches for links that do not point to an existing file
|
||||
local find_args=("$dir" "-xtype" "l")
|
||||
(( one_fs )) && find_args+=("-xdev")
|
||||
|
||||
# Execution logic
|
||||
if (( delete )); then
|
||||
disp W "Deleting dead symlinks in $dir..."
|
||||
find "${find_args[@]}" -delete -print
|
||||
elif (( details )); then
|
||||
find "${find_args[@]}" -ls
|
||||
else
|
||||
find "${find_args[@]}"
|
||||
fi
|
||||
}
|
||||
export -f finddead
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
112
profile.d/fun.sh
Normal file
112
profile.d/fun.sh
Normal file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Make non-IT peoples think you're busy doing something hard
|
||||
# Usage: busy [options] [pattern]
|
||||
# Options:
|
||||
# --delay=<ms> : add a delay between each line output (milliseconds)
|
||||
# pattern : the string to search for in the hexdump output (default is "ca fe")
|
||||
busy()
|
||||
{
|
||||
local pattern="ca fe" delay_ms=0
|
||||
|
||||
local PARSED
|
||||
# Short: h, p:, d:
|
||||
# Long: help, pattern:, delay:
|
||||
PARSED=$(getopt -o hp:d: --long help,pattern:,delay: -n 'busy' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"busy --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "busy: Monitor /dev/urandom for a specific pattern.\n\n"
|
||||
printf "Usage: busy [options] [pattern]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "\t-p, --pattern PATTERN\tHex pattern to search (default: \"ca fe\")\n"
|
||||
printf "\t-d, --delay MS\t\tDelay between matches in milliseconds\n"
|
||||
return 0
|
||||
;;
|
||||
-p|--pattern)
|
||||
pattern="$2"
|
||||
shift 2
|
||||
;;
|
||||
-d|--delay)
|
||||
delay_ms="$2"
|
||||
if ! [[ "$delay_ms" =~ ^[0-9]+$ ]]; then
|
||||
disp E "Invalid delay: must be an integer (milliseconds)."
|
||||
return 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid option: $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Convert milliseconds to seconds for 'sleep'
|
||||
local delay_s=$(awk "BEGIN{
|
||||
printf \"%.3f\", $delay_ms / 1000 }")
|
||||
|
||||
# Monitor /dev/urandom
|
||||
(
|
||||
hexdump -C < /dev/urandom | grep -iF --line-buffered "$pattern" | \
|
||||
while read -r line; do
|
||||
echo "$line"
|
||||
[[ $delay_ms -gt 0 ]] && sleep "$delay_s"
|
||||
done
|
||||
) & local sub_pid=$!
|
||||
|
||||
IFS= read -r -n 1 -s _ </dev/tty
|
||||
kill -- -"$sub_pid" 2>/dev/null || kill "$sub_pid" 2>/dev/null
|
||||
wait "$sub_pid" 2>/dev/null
|
||||
return 0
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
@@ -1,33 +1,84 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Display list of commands and general informations
|
||||
# ------------------------------------------------------------------------------
|
||||
# Usage: help
|
||||
help()
|
||||
{
|
||||
cat <<EOF
|
||||
clean Erase backup files
|
||||
dpkgs Search for the given package in the installed ones
|
||||
gpid Give the list of PIDs for the given process name
|
||||
isipv4 Tell if the given IPv4 is valid
|
||||
isipv6 Tell if the given IPv6 is valid
|
||||
ku Kill process owned by users in parameter
|
||||
mcd Create a directory and go inside
|
||||
meteo Display curent weather forecast for the configured city
|
||||
ppg Display process matching the given parameter
|
||||
rain Let the rain fall
|
||||
rmhost Remove host (IP and/or DNS name) for current known_host
|
||||
rmspc Remove spaces from all the files in working directory
|
||||
setc Set console language to C
|
||||
setfr Set console language to French
|
||||
settrace Activate/deactivate call trace for script debugging
|
||||
setus Set console language to US English
|
||||
showinfo Show the welcoming baner with basic system information
|
||||
ssr Do a root login to the given address
|
||||
taz Compress smartly the given files or directory
|
||||
utaz Uncompress all zip files in the given (or current) directory
|
||||
ver Display version of your copy of profile
|
||||
printf "clean\t\tErase backup files\n"
|
||||
printf "disp\t\tDisplay formatted info/warning/error/debug messages\n"
|
||||
printf "dwl\t\tDownload a URL to a local file\n"
|
||||
printf "expandlist\tExpand and quote item lists\n"
|
||||
printf "file_stats\tDisplay file size statistics for a path\n"
|
||||
printf "findbig\t\tFind biggest files in the given (or current) directory\n"
|
||||
printf "finddead\tFind dead symbolic links in the given (or current) directory\n"
|
||||
printf "findzero\tFind empty files in the given (or current) directory\n"
|
||||
printf "genpwd\t\tGenerate secure passwords\n"
|
||||
printf "gpid\t\tGive the list of PIDs for the given process name\n"
|
||||
printf "isipv4\t\tTell if the given IPv4 is valid\n"
|
||||
printf "isipv6\t\tTell if the given IPv6 is valid\n"
|
||||
printf "ku\t\tKill process owned by users in parameter\n"
|
||||
printf "matrix\t\tDisplay matrix-style digital rain\n"
|
||||
printf "mcd\t\tCreate a directory and go inside\n"
|
||||
printf "meteo\t\tDisplay current weather forecast for the configured city\n"
|
||||
printf "myextip\tDisplay current external/public IP\n"
|
||||
printf "pkgs\t\tSearch for the given package in installed ones\n"
|
||||
printf "ppg\t\tDisplay process matching the given parameter\n"
|
||||
printf "ppn\t\tDisplay process matching the exact process name given in parameter\n"
|
||||
printf "ppu\t\tDisplay processes owned by the given user\n"
|
||||
printf "rain\t\tLet the rain fall\n"
|
||||
printf "rmhost\t\tRemove host (IP and/or DNS name) from current known_hosts\n"
|
||||
printf "rmspc\t\tRemove spaces from file and directory names\n"
|
||||
printf "setlocale\tSet console language to the current locale\n"
|
||||
printf " * setc\tSet console language to C\n"
|
||||
printf " * setfr\tSet console language to French\n"
|
||||
printf " * setus\tSet console language to US English\n"
|
||||
printf "settrace\tActivate/deactivate call trace for script debugging\n"
|
||||
printf "showinfo\tShow welcome banner with basic system information\n"
|
||||
printf "ssr\t\tDo a root login to the given address\n"
|
||||
printf "taz\t\tCompress smartly the given files or directory\n"
|
||||
printf "urlencode\tURL-encode the given text\n"
|
||||
printf "utaz\t\tUncompress archives in the given (or current) directory\n"
|
||||
printf "ver\t\tDisplay version of your copy of profile\n\n"
|
||||
|
||||
Please use <command> --help to obtain usage details.
|
||||
EOF
|
||||
printf "\nPlease use <command> --help to obtain usage details.\n"
|
||||
}
|
||||
export -f help
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
@@ -1,55 +1,179 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Show profile version
|
||||
# ------------------------------------------------------------------------------
|
||||
ver ()
|
||||
# Usage: ver
|
||||
ver()
|
||||
{
|
||||
echo "Profile version $PROFVERSION."
|
||||
local PARSED=$(getopt -o h --long help -n 'ver' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"ver --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "ver: Display the current profile version.\nUsage: ver\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"ver --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -z $PROFVERSION ]] && \
|
||||
disp W "No version defined. Profile is probably badly installed." && \
|
||||
return 1
|
||||
disp "Profile version $PROFVERSION."
|
||||
}
|
||||
export -f ver
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Display weather of the given city (or default one)
|
||||
# ------------------------------------------------------------------------------
|
||||
meteo ()
|
||||
# Usage: meteo [city1 city2 ...]
|
||||
meteo()
|
||||
{
|
||||
cities=$@
|
||||
[[ $# -eq 0 ]] && local cities=$DEFAULT_CITY
|
||||
local PARSED=$(getopt -o h --long help -n 'meteo' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"meteo --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "meteo: Fetch weather data.\nUsage: meteo [city1 city2 ...]\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"meteo --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
for city in $cities; do
|
||||
curl https://wttr.in/$city || echo "Failed fetching datas for $city."
|
||||
local cities=("$@")
|
||||
[[ $# -eq 0 ]] && cities=("$DEFAULT_CITY")
|
||||
|
||||
for city in "${cities[@]}"; do
|
||||
encoded=$(urlencode "$city")
|
||||
dwl "https://wttr.in/$encoded" || \
|
||||
disp E "Failed fetching datas for $city."
|
||||
done
|
||||
}
|
||||
export -f meteo
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Display system general information
|
||||
# ------------------------------------------------------------------------------
|
||||
# Usage: showinfo
|
||||
showinfo()
|
||||
{
|
||||
echo -e "\n"
|
||||
if command -v figlet >/dev/null 2>&1; then
|
||||
if [[ -s /usr/share/figlet/ansi_shadow.flf ]]; then
|
||||
local figopt="-f ansi_shadow"
|
||||
fi
|
||||
figlet -k $(hostname) $figopt
|
||||
local PARSED=$(getopt -o h --long help -n 'showinfo' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"showinfo --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "showinfo: Display system information (hostname, kernel, uptime).\nUsage: showinfo\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"showinfo --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
printf "\n"
|
||||
if command -v figlet >/dev/null 2>&1; then
|
||||
if [[ -s /usr/share/figlet/ansi_shadow.flf ]]; then
|
||||
local figopt="-f ansi_shadow"
|
||||
fi
|
||||
if [[ -n $figopt ]]; then
|
||||
figlet -k $figopt $(hostname)
|
||||
else
|
||||
figlet $(hostname)
|
||||
fi
|
||||
else
|
||||
echo "$(hostname -f)"
|
||||
hostname -f
|
||||
fi
|
||||
echo ""
|
||||
if command -v neofetch >/dev/null 2>&1; then
|
||||
neofetch
|
||||
neofetch
|
||||
elif command -v fastfetch >/dev/null 2>&1; then
|
||||
fastfetch
|
||||
else
|
||||
(
|
||||
if [[ -s /etc/os-release ]]; then
|
||||
. /etc/os-release
|
||||
echo "$NAME $VERSION"
|
||||
else
|
||||
cat /proc/version
|
||||
fi
|
||||
echo "Uptime: $(uptime)"
|
||||
)
|
||||
(
|
||||
if [[ -s /etc/os-release ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
. /etc/os-release
|
||||
printf "$NAME $VERSION\n"
|
||||
else
|
||||
cat /proc/version
|
||||
fi
|
||||
printf "Uptime: $(uptime -p)\n"
|
||||
)
|
||||
fi
|
||||
}
|
||||
export -f showinfo
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
load_conf info
|
||||
# EOF
|
||||
|
||||
@@ -1,35 +1,181 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Change locale to French
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
setfr ()
|
||||
|
||||
locale_check()
|
||||
{
|
||||
# Set fr locale definitions
|
||||
export LANG=fr_FR.UTF-8
|
||||
export LC_MESSAGES=fr_FR.UTF-8
|
||||
export LC_ALL=fr_FR.UTF-8
|
||||
locale -a | grep -qx "$1" || {
|
||||
disp W "Locale '$1' is not installed on this system."
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
export -f setfr
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Change locale to C standard
|
||||
# Change locale to the given one in parameter
|
||||
# Usage: setlocale <locale>
|
||||
setlocale()
|
||||
{
|
||||
local PARSED
|
||||
PARSED=$(getopt -o h --long help -n 'setlocale' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"setlocale --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "setlocale: Configure system environment locale variables.\n\n"
|
||||
printf "Usage: setlocale <locale>\n\n"
|
||||
printf "Options:\n"
|
||||
printf " -h, --help Display this help screen\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"setlocale --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local loc=$1
|
||||
[[ -z $loc ]] && disp E "No locale specified." && return 1
|
||||
|
||||
locale_check "$loc" || return 1
|
||||
|
||||
export LANG=$loc
|
||||
export LC_MESSAGES=$loc
|
||||
export LC_TIME=$loc
|
||||
export LC_NUMERIC=$loc
|
||||
export LC_MONETARY=$loc
|
||||
export LC_COLLATE=$loc
|
||||
export LC_CTYPE=$loc
|
||||
|
||||
disp I "Locale set to $loc."
|
||||
}
|
||||
export -f setlocale
|
||||
# ------------------------------------------------------------------------------
|
||||
setc ()
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Special case : change locale to C standard
|
||||
# Usage: setc
|
||||
setc()
|
||||
{
|
||||
# Locale definitions
|
||||
export LANG=C
|
||||
export LC_MESSAGES=C
|
||||
export LC_ALL=C
|
||||
disp I "Locale changed to standard C (POSIX)."
|
||||
}
|
||||
export -f setc
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Change locale to US (needed by Steam)
|
||||
# ------------------------------------------------------------------------------
|
||||
setus ()
|
||||
# Build dynamic locale shortcuts from SET_LOCALE
|
||||
# Expected format:
|
||||
# SET_LOCALE="fr:fr_FR.UTF-8,us:en_US.UTF-8,es:es_ES.UTF-8"
|
||||
# This creates functions:
|
||||
# setfr, setus, setes, ...
|
||||
build_locale_shortcuts()
|
||||
{
|
||||
# Locale definitions
|
||||
export LANG=en_US.UTF-8
|
||||
export LC_MESSAGES=en_US.UTF-8
|
||||
export LC_ALL=en_US.UTF-8
|
||||
local cfg="${SET_LOCALE:-}"
|
||||
local item="" alias="" loc="" fname=""
|
||||
local -a locale_items=()
|
||||
|
||||
[[ -z "$cfg" ]] && return 0
|
||||
|
||||
IFS=',' read -r -a locale_items <<< "$cfg"
|
||||
for item in "${locale_items[@]}"; do
|
||||
# Trim surrounding spaces
|
||||
item="${item#"${item%%[![:space:]]*}"}"
|
||||
item="${item%"${item##*[![:space:]]}"}"
|
||||
|
||||
[[ -z "$item" ]] && continue
|
||||
|
||||
if [[ "$item" != *:* ]]; then
|
||||
disp W "Ignoring invalid SET_LOCALE entry: '$item' (expected alias:locale)."
|
||||
continue
|
||||
fi
|
||||
|
||||
alias="${item%%:*}"
|
||||
loc="${item#*:}"
|
||||
|
||||
# Trim alias/locale spaces
|
||||
alias="${alias#"${alias%%[![:space:]]*}"}"
|
||||
alias="${alias%"${alias##*[![:space:]]}"}"
|
||||
loc="${loc#"${loc%%[![:space:]]*}"}"
|
||||
loc="${loc%"${loc##*[![:space:]]}"}"
|
||||
|
||||
# Validate alias for safe function names
|
||||
if [[ ! "$alias" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then
|
||||
disp W "Ignoring unsafe locale alias '$alias' in SET_LOCALE."
|
||||
continue
|
||||
fi
|
||||
|
||||
[[ -z "$loc" ]] && {
|
||||
disp W "Ignoring empty locale for alias '$alias' in SET_LOCALE."
|
||||
continue
|
||||
}
|
||||
|
||||
fname="set${alias}"
|
||||
|
||||
# Optional collision warning
|
||||
if declare -F "$fname" >/dev/null 2>&1; then
|
||||
disp W "Overriding existing function '$fname'."
|
||||
fi
|
||||
|
||||
# Build function dynamically
|
||||
# shellcheck disable=SC2016
|
||||
eval "${fname}() { setlocale \"$loc\"; }"
|
||||
# shellcheck disable=SC2163
|
||||
export -f "$fname"
|
||||
done
|
||||
|
||||
unset cfg item alias loc fname locale_items
|
||||
}
|
||||
export -f setus
|
||||
export -f build_locale_shortcuts
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
load_conf lang
|
||||
build_locale_shortcut
|
||||
# ------------------------------------------------------------------------------
|
||||
# EOF
|
||||
|
||||
277
profile.d/net.sh
277
profile.d/net.sh
@@ -1,49 +1,272 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Download a resource using curl, wget, or fetch.
|
||||
# Usage: dwl <url> [output_file]
|
||||
dwl()
|
||||
{
|
||||
case "$1" in
|
||||
--help|-h)
|
||||
echo "Usage: dwl <url> [output_file]"
|
||||
echo "Downloads a resource using curl, wget, or fetch."
|
||||
echo ""
|
||||
echo "Arguments:"
|
||||
echo " url The full URL to download (http/https/ftp)."
|
||||
echo " output_file (Optional) Path to save the file. If omitted, prints to stdout."
|
||||
return 0
|
||||
;;
|
||||
"")
|
||||
echo "Error: URL argument is missing." >&2
|
||||
echo "Try 'get_resource --help' for usage." >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$1" in
|
||||
http://*|https://*|ftp://*) ;;
|
||||
*)
|
||||
echo "Error: '$1' does not look like a valid URL. Must start with http://, https://, or ftp://" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
local url="$1"
|
||||
local output="$2"
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
[ -z "$output" ] && curl -sL "$url" || curl -sL -o "$output" "$url"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
[ -z "$output" ] && wget -qO- "$url" || wget -q -O "$output" "$url"
|
||||
elif command -v fetch >/dev/null 2>&1; then
|
||||
[ -z "$output" ] && fetch -o - "$url" || fetch -o "$output" "$url"
|
||||
else
|
||||
echo "Error: No download utility (curl, wget, or fetch) found." >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
export -f dwl
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Determine if parameter is a valid IPv4 address
|
||||
# ------------------------------------------------------------------------------
|
||||
isipv4 ()
|
||||
# Usage: isipv4 <ip_address>
|
||||
isipv4()
|
||||
{
|
||||
# Set up local variables
|
||||
local ip=$1
|
||||
local ip=$1
|
||||
[[ -z $ip ]] && return 1
|
||||
|
||||
# Start with a regex format test
|
||||
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
local old_ifs=$IFS
|
||||
IFS="."
|
||||
ip=($ip)
|
||||
IFS=$old_ifs
|
||||
if [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
|
||||
&& ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]; then
|
||||
if [[ -t 1 ]]; then
|
||||
echo "The given IPv4 is valid."
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
if [[ -t 1 ]]; then
|
||||
echo "The given parameter is NOT a valid IPv4."
|
||||
# Start with a regex format test (four octets)
|
||||
if [[ $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
|
||||
local old_ifs=$IFS
|
||||
IFS='.'
|
||||
read -r -a ip_arr <<< "$ip"
|
||||
IFS=$old_ifs
|
||||
|
||||
# Ensure each octet is between 0 and 255
|
||||
local oct
|
||||
for oct in "${ip_arr[@]}"; do
|
||||
# Reject leading plus/minus or empty entries
|
||||
if [[ -z $oct || $oct =~ [^0-9] ]]; then
|
||||
[[ -t 1 ]] && disp "The given parameter is NOT a valid IPv4."
|
||||
return 1
|
||||
fi
|
||||
if (( oct > 255 )); then
|
||||
[[ -t 1 ]] && disp "The given parameter is NOT a valid IPv4."
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
[[ -t 1 ]] && disp "The given IPv4 is valid."
|
||||
return 0
|
||||
fi
|
||||
|
||||
[[ -t 1 ]] && disp "The given parameter is NOT a valid IPv4."
|
||||
return 1
|
||||
}
|
||||
export -f isipv4
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Determine if parameter is a valid IPv4 address
|
||||
# ------------------------------------------------------------------------------
|
||||
isipv6 ()
|
||||
# Determine if parameter is a valid IPv6 address
|
||||
# Usage: isipv6 <ip_address>
|
||||
isipv6()
|
||||
{
|
||||
local ip="$1"
|
||||
local regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'
|
||||
if [[ $ip =~ $regex ]]; then
|
||||
if [[ -t 1 ]]; then
|
||||
echo "The given IPv6 is valid."
|
||||
fi
|
||||
return 0
|
||||
if [[ -t 1 ]]; then
|
||||
disp "The given IPv6 is valid."
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
if [[ -t 1 ]]; then
|
||||
echo "The given parameter is not a valid IPv6."
|
||||
disp "The given parameter is not a valid IPv6."
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
export -f isipv6
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Encode a string so it can be used as a URL parameter
|
||||
# Usage: urlencode <string>
|
||||
urlencode() {
|
||||
local LANG=C
|
||||
local str="$*"
|
||||
local length="${#str}"
|
||||
for (( i = 0; i < length; i++ )); do
|
||||
local c="${str:i:1}"
|
||||
case "$c" in
|
||||
[a-zA-Z0-9.~_-]) printf '%s' "$c" ;;
|
||||
' ') printf '+' ;;
|
||||
*) printf '%%%02X' "'$c" #| cut -d' ' -f2 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
export -f urlencode
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Fetch and display external IP information
|
||||
# Usage: myextip [-i|--ip] [-s|--isp] [-l|--loc] [-c|--coord]
|
||||
# If no option is provided, all information will be displayed.
|
||||
# Options:
|
||||
# -h, --help Display help screen
|
||||
# -i, --ip Display only the external IP address
|
||||
# -s, --isp Display only the ISP name
|
||||
# -l, --loc Display only the location (city, region, country)
|
||||
# -c, --coord Display only the coordinates (latitude, longitude)
|
||||
# -a, --as Display only the Autonomous System (AS) information
|
||||
# -R, --raw Display raw JSON response
|
||||
myextip() {
|
||||
local show_ip=false show_isp=false show_loc=false
|
||||
local show_coord=false show_as=false show_raw=false
|
||||
local all=true
|
||||
|
||||
# Parse arguments
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-i|--ip)
|
||||
show_ip=true
|
||||
all=false
|
||||
;;
|
||||
-s|--isp)
|
||||
show_isp=true
|
||||
all=false
|
||||
;;
|
||||
-l|--loc)
|
||||
show_loc=true
|
||||
all=false
|
||||
;;
|
||||
-c|--coord)
|
||||
show_coord=true
|
||||
all=false
|
||||
;;
|
||||
-a|--as)
|
||||
show_as=true
|
||||
all=false
|
||||
;;
|
||||
-R|--raw)
|
||||
all=false
|
||||
show_raw=true
|
||||
;;
|
||||
-h|--help)
|
||||
printf "Fetch and display external IP information.\n\n"
|
||||
printf "Usage: myextip [-i|--ip] [-s|--isp] [-l|--loc] [-c|--coord] [-a|--as] [-R|--raw]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\tDisplay this help screen\n"
|
||||
printf "\t-i, --ip\tDisplay only the external IP address\n"
|
||||
printf "\t-s, --isp\tDisplay only the ISP name\n"
|
||||
printf "\t-l, --loc\tDisplay only the location (city, region, country)\n"
|
||||
printf "\t-c, --coord\tDisplay only the coordinates (latitude, longitude)\n"
|
||||
printf "\t-a, --as\tDisplay only the Autonomous System (AS) information\n"
|
||||
printf "\t-R, --raw\tDisplay raw JSON response\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Unknown option: $1, use \"myextip --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# Fetch data. Allow overriding endpoint via env var MYEXTIP_URL
|
||||
local MYEXTIP_URL
|
||||
MYEXTIP_URL=${MYEXTIP_URL:-http://ip-api.com/json/}
|
||||
|
||||
local response
|
||||
if ! response=$(dwl "$MYEXTIP_URL"); then
|
||||
disp E "Failed to fetch external IP information from $MYEXTIP_URL"
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Parse with jq when available and when raw wasn't requested. The jq filter
|
||||
# is tolerant to field-name differences between providers (ip-api / ipinfo).
|
||||
if command -v jq >/dev/null 2>&1 && [[ "$show_raw" != true ]]; then
|
||||
echo "$response" | jq -r --argjson all "$all" --argjson ip "$show_ip" \
|
||||
--argjson isp "$show_isp" --argjson loc "$show_loc" \
|
||||
--argjson coord "$show_coord" --argjson as "$show_as" '
|
||||
[
|
||||
(if $all or $ip then "IP Address : \(.query // .ip)" else empty end),
|
||||
(if $all or $isp then "ISP : \(.isp // .org)" else empty end),
|
||||
(if $all or $loc then
|
||||
("Location : " + ((.city // "") + (if .city then ", " else "" end) + (if .regionName then .regionName else .region end) + (if .country then ", " + .country else "" end)))
|
||||
else empty end),
|
||||
(if $all or $coord then (if (.lat and .lon) then "Coordinates: \(.lat), \(.lon)" elif .loc then "Coordinates: \(.loc)" else empty end) else empty end),
|
||||
(if $all or $as then "AS : \(.as // .org)" else empty end)
|
||||
] | .[]'
|
||||
else
|
||||
[[ "$show_raw" != true ]] && disp W "jq is not installed, displaying raw JSON response."
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
export -f myextip
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# EOF
|
||||
|
||||
@@ -1,42 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Look for a package within installed one
|
||||
# ------------------------------------------------------------------------------
|
||||
dpkgs ()
|
||||
# Usage: dpkgs <string>
|
||||
pkgs()
|
||||
{
|
||||
local count=0
|
||||
for opt in $@ ; do
|
||||
case $opt in
|
||||
"-h"|"--help")
|
||||
echo "dpkgs: look for an installed package by it's name."
|
||||
echo
|
||||
echo "Usage: dpkgs <string>"
|
||||
local ignore_case=0
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hi --long help,ignore-case -n 'pkgs' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"pkgs --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "pkgs: Look for an installed package by its name.\n\n"
|
||||
printf "Usage: pkgs [options] <string>\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\tDisplay this help screen\n"
|
||||
printf "\t-i, --ignore-case\tIgnore case distinctions\n"
|
||||
return 0
|
||||
;;
|
||||
|
||||
"-"*)
|
||||
echo "Invalid option, use \"dpkgs --help\" to display usage."
|
||||
echo
|
||||
return 1
|
||||
-i|--ignore-case)
|
||||
ignore_case=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
|
||||
*)
|
||||
local pkg=$1 && shift
|
||||
count=$(( $count + 1 ))
|
||||
[[ $count -gt 1 ]] &&
|
||||
echo "*** Error: Please specify a package name, without space, eventually partial." &&
|
||||
return 1
|
||||
|
||||
disp E "Invalid option: $1"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
[[ $count -lt 1 ]] &&
|
||||
echo "*** Error: Please specify a package name, without space, eventually partial." &&
|
||||
|
||||
local pkg="$1"
|
||||
[[ -z "$pkg" ]] && {
|
||||
disp E "Please specify a package name, without space, eventually partial."
|
||||
return 1
|
||||
}
|
||||
|
||||
[[ -x /usr/sbin/dpkg ]] &&
|
||||
echo "*** Error: dpkg command seems unavialable." &&
|
||||
# Build grep command
|
||||
local grep_opt=""
|
||||
(( ignore_case )) && grep_opt="-i"
|
||||
|
||||
command -v dpkg >/dev/null 2>&1 && local cmd="dpkg -l"
|
||||
command -v rpm >/dev/null 2>&1 && local cmd="rpm -qa"
|
||||
if [[ -z $cmd ]]; then
|
||||
disp E "No usable package manager seems unavialable."
|
||||
return 2
|
||||
|
||||
dpkg -l | grep $pkg
|
||||
fi
|
||||
$cmd | grep $grep_opt $pkg
|
||||
}
|
||||
export -f dpkgs
|
||||
export -f pkgs
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
@@ -1,18 +1,128 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Search processes matching the given string
|
||||
# ------------------------------------------------------------------------------
|
||||
ppg ()
|
||||
# Usage: ppg <string>
|
||||
ppg()
|
||||
{
|
||||
ps -edf | grep $@ | grep -v "grep $@"
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "ppg: Search processes matching the given string.\n\n"
|
||||
printf "Usage: ppg <string>\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "$1" ]]; then
|
||||
disp E "Usage: ppg <string>"
|
||||
return 1
|
||||
fi
|
||||
ps -edf | grep "$@" | grep -v "grep $@"
|
||||
}
|
||||
export -f ppg
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# List processes owned by a specific user
|
||||
# Usage: ppu <username>
|
||||
ppu()
|
||||
{
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "ppu: List processes owned by a specific user.\n\n"
|
||||
printf "Usage: ppu <username>\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "$1" ]]; then
|
||||
disp E "Usage: ppu <username>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# -u lists processes for a specific user
|
||||
# -o provides a clean, standard output format
|
||||
ps -u "$1" -o pid,user,%cpu,%mem,start,time,command
|
||||
}
|
||||
export -f ppu
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# List processes by exact command name (no path/parameters)
|
||||
# Usage: ppn <command_name>
|
||||
ppn()
|
||||
{
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "ppn: List processes by exact command name (no path/parameters).\n\n"
|
||||
printf "Usage: ppn <command_name>\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "$1" ]]; then
|
||||
disp E "Usage: ppn <command_name>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# -e: select all processes
|
||||
# -o: specify custom output columns (PID and Command name)
|
||||
# grep -w: ensures exact word matching so 'bash' doesn't match 'dbash'
|
||||
ps -eo pid,comm | grep -w "$1"
|
||||
}
|
||||
export -f ppn
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Get PID list of the given process name
|
||||
# ------------------------------------------------------------------------------
|
||||
gpid ()
|
||||
# Usage: ppid <process_name [process_name2 ...]>
|
||||
gpid()
|
||||
{
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "gpid: Get PID list of the given process name.\n\n"
|
||||
printf "Usage: gpid <process_name [process_name2 ...]>\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "$1" ]]; then
|
||||
disp E "Usage: gpid <process_name [process_name2 ...]>"
|
||||
return 1
|
||||
fi
|
||||
[[ $UID -eq 0 ]] && local psopt="-A"
|
||||
[[ $# -eq 1 ]] && local single=1
|
||||
for pid in $@; do
|
||||
@@ -26,15 +136,65 @@ gpid ()
|
||||
[[ $result ]] || return 1
|
||||
}
|
||||
export -f gpid
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kill all processes owned by the given users
|
||||
# ------------------------------------------------------------------------------
|
||||
ku ()
|
||||
# Kill all processes owned by the given users (kill user)
|
||||
# Usage: ku <username1 [username2 ...]>
|
||||
ku()
|
||||
{
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "ku: Kill all processes owned by the given users.\n\n"
|
||||
printf "Usage: ku <username1 [username2 ...]>\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "$1" ]]; then
|
||||
disp E "Usage: ku <username1 [username2 ...]>"
|
||||
return 1
|
||||
fi
|
||||
for u in $@; do
|
||||
killall -u $u
|
||||
killall -u "$u"
|
||||
done
|
||||
}
|
||||
export -f ku
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kill all children of a process then the process (kill tree)
|
||||
# Usage: kt <pid> [kill_options]
|
||||
kt()
|
||||
{
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "kt: Kill all children of a process then the process (kill tree).\n\n"
|
||||
printf "Usage: kt <pid> [kill_options]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "$1" ]]; then
|
||||
disp E "Usage: ppg <string>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local parent_pid="$1"
|
||||
shift
|
||||
if [[ "$parent_pid" == "0" || "$parent_pid" == "1" ]]; then
|
||||
disp E "Safety abort: Refusing to kill PID $parent_pid (system critical)."
|
||||
return 1
|
||||
fi
|
||||
|
||||
children_pids=$(pgrep -P "$parent_pid")
|
||||
|
||||
for pid in $children_pids; do
|
||||
kt "$pid" "$@" || break
|
||||
done
|
||||
kill "$@" "$parent_pid"
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
@@ -1,16 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# timer_* functions : internal timing function for prompt
|
||||
# ------------------------------------------------------------------------------
|
||||
# Usage: timer_now
|
||||
# This function returns the current time in nanoseconds since the epoch. It
|
||||
# first tries to use the %N format specifier for nanoseconds, but if that is
|
||||
# not supported (e.g., on older systems), it falls back to seconds.
|
||||
function timer_now
|
||||
{
|
||||
date +%s%N
|
||||
date +%s%N 2>/dev/null || date +%s
|
||||
}
|
||||
|
||||
# Usage: timer_start
|
||||
# This function initializes the timer_start variable with the current time in
|
||||
# nanoseconds. It is used to measure the elapsed time for the prompt.
|
||||
function timer_start
|
||||
{
|
||||
timer_start=${timer_start:-$(timer_now)}
|
||||
}
|
||||
|
||||
# Usage: timer_stop
|
||||
# This function calculates the elapsed time since timer_start and formats it
|
||||
# into a human-readable string with appropriate units (us, ms, s, m, h
|
||||
function timer_stop
|
||||
{
|
||||
local delta_us=$((($(timer_now) - $timer_start) / 1000))
|
||||
@@ -39,23 +84,26 @@ function timer_stop
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Function triguered internaly by bash : defining prompt
|
||||
# ------------------------------------------------------------------------------
|
||||
set_prompt ()
|
||||
# Function triggered internally by bash : defining prompt
|
||||
# Usage: set_prompt
|
||||
# This function is called by bash before displaying the prompt. It sets the
|
||||
# PS1 variable to a custom prompt that includes the exit status of the last
|
||||
# command, the elapsed time of the last command, and the current user and host.
|
||||
set_prompt()
|
||||
{
|
||||
Last_Command=$? # Must come first!
|
||||
Blue='\[\e[0;34m\]'
|
||||
White='\[\e[01;37m\]'
|
||||
Yellow='\[\e[01;93m\]'
|
||||
Red='\[\e[01;31m\]'
|
||||
Green='\[\e[01;32m\]'
|
||||
OnGrey='\[\e[47m\]'
|
||||
OnRed='\[\e[41m\]'
|
||||
OnBlue='\[\e[44m\]'
|
||||
ICyan='\[\e[0;96m\]'
|
||||
Default='\[\e[00m\]'
|
||||
FancyX='\342\234\227'
|
||||
Checkmark='\342\234\223'
|
||||
local Last_Command=$? # Must come first!
|
||||
local Blue='\[\e[0;34m\]'
|
||||
local White='\[\e[01;37m\]'
|
||||
local Yellow='\[\e[01;93m\]'
|
||||
local Red='\[\e[01;31m\]'
|
||||
local Green='\[\e[01;32m\]'
|
||||
local OnGrey='\[\e[47m\]'
|
||||
local OnRed='\[\e[41m\]'
|
||||
local OnBlue='\[\e[44m\]'
|
||||
local ICyan='\[\e[0;96m\]'
|
||||
local Default='\[\e[00m\]'
|
||||
local FancyX='\342\234\227'
|
||||
local Checkmark='\342\234\223'
|
||||
|
||||
# Begin with time
|
||||
PS1="\[\e[s$Blue$OnGrey [ \t ] $OnBlue"
|
||||
@@ -88,3 +136,7 @@ set_prompt ()
|
||||
# the text color to the default.
|
||||
PS1+="$ICyan\\w \\\$$Default "
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
309
profile.d/pwd.sh
Executable file → Normal file
309
profile.d/pwd.sh
Executable file → Normal file
@@ -1,144 +1,203 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# genpwd : generate a password with different criteria
|
||||
# default 16 car with up and low car, symbol and number
|
||||
# Usage: genpwd [options] [--extracars=<cars>] [--length=<n>] [nb_passwd]
|
||||
# Options:
|
||||
# -h, --help Display that help screen
|
||||
# -s, --nosymbols Exclude symbols
|
||||
# -n, --nonumbers Exclude numbers
|
||||
# -u, --noup Exclude uppercase letters
|
||||
# -l, --nolow Exclude lowercase letters
|
||||
# -e=<c>, --extracars=<c>
|
||||
# Add the given caracters to the possible caracter list
|
||||
# -L=<n>, --length=<n>
|
||||
# Set length of the password (default is 16)
|
||||
# -o=<n>, --occurences=<n>
|
||||
# Set the maximum occurences of a same caracter (default is 2)
|
||||
# The function is very slow on Windows
|
||||
# ------------------------------------------------------------------------------
|
||||
genpwd()
|
||||
{
|
||||
local length=16
|
||||
local occurs=2 # Bug, if set to 1, seems to be ignored
|
||||
local symb=1 maj=1 min=1 numb=1
|
||||
local nbpwd=1
|
||||
|
||||
for opt in $@; do
|
||||
case $opt in
|
||||
"-h"|"--help")
|
||||
echo "genpwd: generate a secure random password."
|
||||
echo
|
||||
echo "Usage: genpwd [options] [--extracars=<cars>] [--length=<n>] [nb_passwd]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -h, --help Display that help screen"
|
||||
echo " -s, --nosymbols Exclude symbols"
|
||||
echo " -n, --nonumbers Exclude numbers"
|
||||
echo " -u, --noup Exclude uppercase letters"
|
||||
echo " -l, --nolow Exclude lowercase letters"
|
||||
echo " -e=<c>, --extracars=<c>"
|
||||
echo " Add the given caracters to the possible caracter list"
|
||||
echo " -L=<n>, --length=<n>"
|
||||
echo " Set length of the password (default is $length)"
|
||||
echo " -o=<n>, --occurences=<n>"
|
||||
echo " Set the maximum occurences of a same caracter (default is $occurs)"
|
||||
echo
|
||||
echo "If the --extracars parameter is given, at least one of the given caracter will"
|
||||
echo "be used in the final password."
|
||||
echo
|
||||
echo "Please note that some caracters might be interpreted by Bash or Awk programs,"
|
||||
echo "and thus, cannot be used without provoquing errors. Those identified caracters"
|
||||
echo "are :"
|
||||
echo ' * ? \ $ { }'
|
||||
echo
|
||||
return 0
|
||||
;;
|
||||
"-s"|"--nosymbols")
|
||||
symb=0
|
||||
;;
|
||||
"-n"|"--nonumbers")
|
||||
numb=0
|
||||
;;
|
||||
"-u"|"--noup")
|
||||
maj=0
|
||||
;;
|
||||
"-l"|"--nolow")
|
||||
min=0
|
||||
;;
|
||||
"-e"?*|"--extracars"?*)
|
||||
local extcar=$(echo "$opt" | cut -f 2- -d '=')
|
||||
;;
|
||||
"-L"?*|"--length"?*)
|
||||
local length=$(echo "$opt" | cut -f 2- -d '=')
|
||||
if ! [[ $length =~ ^[0-9]+$ ]]; then
|
||||
echo "The --length parameter requires a number."
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
"-o"?*|"--occurences"?*)
|
||||
local occurs=$(echo "$opt" | cut -f 2- -d '=')
|
||||
if ! [[ $occurs =~ ^[1-9]+$ ]]; then
|
||||
echo "The --occurs parameter requires a number from 1 to 9."
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
"-*")
|
||||
echo "Unknow parameter ${opt}."
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
if ! [[ $opt =~ ^[1-9]+$ ]]; then
|
||||
echo "Unknow parameter ${opt}."
|
||||
return 1
|
||||
else
|
||||
local nbpwd=$opt
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
local extcar
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hsnu l e:L:o: --long \
|
||||
help,nosymbols,nonumbers,noup,nolow,extracars:,length:,occurences: -n 'genpwd' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then return 1; fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "genpwd: Generate secure random password(s).\n\n"
|
||||
printf "Usage: genpwd [options] [nb_passwd]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "\t-s, --nosymbols\t\tExclude symbols\n"
|
||||
printf "\t-n, --nonumbers\t\tExclude numbers\n"
|
||||
printf "\t-u, --noup\t\tExclude uppercase letters\n"
|
||||
printf "\t-l, --nolow\t\tExclude lowercase letters\n"
|
||||
printf "\t-e, --extracars <c>\tAdd characters to list\n"
|
||||
printf "\t-L, --length <n>\tSet password length (default: 16)\n"
|
||||
printf "\t-o, --occurences <n>\tMax occurences per character (default: 2)\n"
|
||||
return 0
|
||||
;;
|
||||
-s|--nosymbols)
|
||||
symb=0
|
||||
shift
|
||||
;;
|
||||
-n|--nonumbers)
|
||||
numb=0
|
||||
shift
|
||||
;;
|
||||
-u|--noup)
|
||||
maj=0
|
||||
shift
|
||||
;;
|
||||
-l|--nolow)
|
||||
min=0
|
||||
shift
|
||||
;;
|
||||
-e|--extracars)
|
||||
extcar="$2"
|
||||
shift 2
|
||||
;;
|
||||
-L|--length)
|
||||
length="$2"
|
||||
if ! [[ $length =~ ^[0-9]+$ ]]; then
|
||||
disp E "The --length parameter requires a number."
|
||||
return 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
-o|--occurences)
|
||||
occurs="$2"
|
||||
if ! [[ $occurs =~ ^[1-9]+$ ]]; then
|
||||
disp E "The --occurs parameter requires a number from 1 to 9."
|
||||
return 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift; break
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -n "$1" ]]; then
|
||||
nbpwd="$1"
|
||||
if ! [[ $nbpwd =~ ^[0-9]+$ ]]; then
|
||||
disp E "The number of password to generate must be a number."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Function selecting a random caracter from the list in parameter
|
||||
pickcar()
|
||||
{
|
||||
# When a character is picked we check if it's not appearing already twice
|
||||
# elsewhere, we choose an other char, to compensate weak bash randomizer
|
||||
while [[ -z $char ]]; do
|
||||
local char=$(echo ${1:RANDOM%${#1}:1} $RANDOM)
|
||||
if [[ $(awk -F"$char" '{print NF-1}' <<< "$picked") -gt $occurs ]]; then
|
||||
unset char
|
||||
fi
|
||||
done
|
||||
picked+="$char"
|
||||
echo "$char"
|
||||
pickcar() {
|
||||
# When a character is picked we check if it's not appearing already twice
|
||||
# elsewhere, we choose an other char, to compensate weak bash randomizer
|
||||
while [[ -z $char ]]; do
|
||||
local char="${1:RANDOM%${#1}:1} $RANDOM"
|
||||
if [[ $(awk -F"$char" '{print NF-1}' <<<"$picked") -gt $occurs ]]; then
|
||||
unset char
|
||||
fi
|
||||
done
|
||||
picked+="$char"
|
||||
echo "$char"
|
||||
}
|
||||
|
||||
echo "Generating $nbpwd passwords, please wait..."
|
||||
for n in $( seq 1 $nbpwd ); do
|
||||
{
|
||||
local carset='' # store final caracter set to use
|
||||
local picked='' # store already used caracter
|
||||
local rlength=0 # store already assigned length of caracters
|
||||
disp I "Generating $nbpwd passwords, please wait..."
|
||||
for (( n=1; n<=nbpwd; n++ )); do
|
||||
{
|
||||
local carset='' # store final caracter set to use
|
||||
local picked='' # store already used caracter
|
||||
local rlength=0 # store already assigned length of caracters
|
||||
|
||||
# ?, *, $ and \ impossible to use to my knowledge as it would be interpreted
|
||||
if [[ $symb == 1 ]]; then
|
||||
pickcar '!.@#&%/^-_'
|
||||
carset+='!.@#&%/^-_'
|
||||
(( rlength++ ))
|
||||
fi
|
||||
if [[ $numb == 1 ]]; then
|
||||
pickcar '0123456789'
|
||||
carset+='0123456789'
|
||||
(( rlength++ ))
|
||||
fi
|
||||
if [[ $maj == 1 ]]; then
|
||||
pickcar 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
carset+='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
(( rlength++ ))
|
||||
fi
|
||||
if [[ $min == 1 ]]; then
|
||||
pickcar 'abcdefghijklmnopqrstuvwxyz'
|
||||
carset+='abcdefghijklmnopqrstuvwxyz'
|
||||
(( rlength++ ))
|
||||
fi
|
||||
if [[ -n $extcar ]]; then
|
||||
pickcar "$extcar"
|
||||
carset+=$extcar
|
||||
(( rlength++ ))
|
||||
fi
|
||||
# ?, *, $ and \ impossible to use to my knowledge as it would be interpreted
|
||||
if [[ $symb == 1 ]]; then
|
||||
pickcar '!.@#&%/^-_'
|
||||
carset+='!.@#&%/^-_'
|
||||
((rlength++))
|
||||
fi
|
||||
if [[ $numb == 1 ]]; then
|
||||
pickcar '0123456789'
|
||||
carset+='0123456789'
|
||||
((rlength++))
|
||||
fi
|
||||
if [[ $maj == 1 ]]; then
|
||||
pickcar 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
carset+='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
((rlength++))
|
||||
fi
|
||||
if [[ $min == 1 ]]; then
|
||||
pickcar 'abcdefghijklmnopqrstuvwxyz'
|
||||
carset+='abcdefghijklmnopqrstuvwxyz'
|
||||
((rlength++))
|
||||
fi
|
||||
if [[ -n $extcar ]]; then
|
||||
pickcar "$extcar"
|
||||
carset+=$extcar
|
||||
((rlength++))
|
||||
fi
|
||||
|
||||
for i in $( seq 1 $(( $length - $rlength )) ); do
|
||||
pickcar "$carset"
|
||||
done
|
||||
} | sort -R | awk '{printf "%s", $1}'
|
||||
unset picked carset rlength
|
||||
echo
|
||||
# Check if we have enough car to have something viable
|
||||
if [[ ${#carset} -lt $length ]]; then
|
||||
disp E 'Not enought caracters are authorised for the password length.'
|
||||
disp E 'Please allow more caracter (preferably) or reduce password lentgh.'
|
||||
return 1
|
||||
fi
|
||||
|
||||
for i in $(seq 1 $(($length - $rlength))); do
|
||||
pickcar "$carset"
|
||||
done
|
||||
} | sort -R | awk '{printf "%s", $1}'
|
||||
unset picked carset rlength
|
||||
echo
|
||||
done
|
||||
}
|
||||
export -f genpwd
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
@@ -1,119 +1,433 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Let the rain fall
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
rain()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Generic rain-like engine and presets
|
||||
|
||||
_rain_build_colors()
|
||||
{
|
||||
local exit_st=0
|
||||
local rain_cars=("|" "│" "┃" "┆" "┇" "┊" "┋" "╽" "╿")
|
||||
local rain_colors=("\e[37m" "\e[37;1m")
|
||||
# More from 256 color mode
|
||||
for i in {244..255}; do
|
||||
rain_colors=( "${rain_colors[@]}" "\e[38;5;${i}m" )
|
||||
done
|
||||
local rain_tab=${#rain_cars[@]}
|
||||
local rain_color_tab=${#rain_colors[@]}
|
||||
local num_rain_metadata=5
|
||||
local term_height=$(tput lines)
|
||||
local term_width=$(tput cols)
|
||||
local step_duration=0.050
|
||||
local X=0 Y=0 drop_length=0 rain_drop=0
|
||||
local max_rain_width=0 new_rain_odd=0 falling_odd=0
|
||||
local base_color="$1"
|
||||
RAIN_ENGINE_COLORS=()
|
||||
|
||||
case $base_color in
|
||||
green)
|
||||
for i in {22..28} {34..40} {46..48}; do RAIN_ENGINE_COLORS+=("\e[38;5;${i}m"); done ;;
|
||||
blue)
|
||||
for i in {17..21} {27..33} {39..45}; do RAIN_ENGINE_COLORS+=("\e[38;5;${i}m"); done ;;
|
||||
red)
|
||||
for i in {52..52} {88..88} {124..124} {160..160} {196..201}; do RAIN_ENGINE_COLORS+=("\e[38;5;${i}m"); done ;;
|
||||
yellow)
|
||||
for i in {58..58} {100..100} {142..142} {184..184} {226..229}; do RAIN_ENGINE_COLORS+=("\e[38;5;${i}m"); done ;;
|
||||
cyan)
|
||||
for i in {30..31} {37..38} {44..45} {50..51}; do RAIN_ENGINE_COLORS+=("\e[38;5;${i}m"); done ;;
|
||||
*)
|
||||
RAIN_ENGINE_COLORS=("\e[37m" "\e[37;1m")
|
||||
for i in {244..255}; do RAIN_ENGINE_COLORS+=("\e[38;5;${i}m"); done ;;
|
||||
esac
|
||||
}
|
||||
|
||||
sigwinch() {
|
||||
term_width=$(tput cols)
|
||||
term_height=$(tput lines)
|
||||
#step_duration=0.025
|
||||
(( max_rain_width = term_width * term_height / 4 ))
|
||||
(( max_rain_height = term_height < 10 ? 1 : term_height / 10 ))
|
||||
# In percentage
|
||||
(( new_rain_odd = term_height > 50 ? 100 : term_height * 2 ))
|
||||
(( new_rain_odd = new_rain_odd * 75 / 100 ))
|
||||
(( falling_odd = term_height > 25 ? 100 : term_height * 4 ))
|
||||
(( falling_odd = falling_odd * 90 / 100 ))
|
||||
_rain_build_chars()
|
||||
{
|
||||
local mode="$1"
|
||||
local charset="$2"
|
||||
RAIN_ENGINE_CHARS=()
|
||||
|
||||
case "$mode" in
|
||||
matrix)
|
||||
case "$charset" in
|
||||
""|binary)
|
||||
RAIN_ENGINE_CHARS=("0" "1")
|
||||
;;
|
||||
kana|kanji)
|
||||
# Half-width katakana set, generally rendered as single-cell glyphs.
|
||||
RAIN_ENGINE_CHARS=("ア" "イ" "ウ" "エ" "オ" "カ" "キ" "ク" "ケ" "コ" "サ" "シ" "ス" "セ" "ソ" "タ" "チ" "ツ" "テ" "ト" "ナ" "ニ" "ヌ" "ネ" "ノ" "ハ" "ヒ" "フ" "ヘ" "ホ" "マ" "ミ" "ム" "メ" "モ" "ヤ" "ユ" "ヨ" "ラ" "リ" "ル" "レ" "ロ" "ワ" "ン")
|
||||
;;
|
||||
ascii)
|
||||
RAIN_ENGINE_CHARS=("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "A" "B" "C" "D" "E" "F")
|
||||
;;
|
||||
*)
|
||||
disp E "Unknown charset: ${charset} (supported: binary, kana, ascii)."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
RAIN_ENGINE_CHARS=("|" "│" "┃" "┆" "┇" "┊" "┋" "╽" "╿")
|
||||
;;
|
||||
esac
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_rain_normalize_speed()
|
||||
{
|
||||
local raw_speed="$1"
|
||||
|
||||
# Accept integer/floating values. UI scale is centiseconds by default:
|
||||
# 5 -> 0.05s, 2.5 -> 0.025s. Values < 1 are treated as direct seconds
|
||||
# for backward compatibility (e.g. 0.03).
|
||||
if [[ ! "$raw_speed" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if awk -v s="$raw_speed" 'BEGIN { exit !(s < 1) }'; then
|
||||
printf "%s" "$raw_speed"
|
||||
else
|
||||
awk -v s="$raw_speed" 'BEGIN { printf "%.3f", s / 100 }'
|
||||
fi
|
||||
}
|
||||
|
||||
_rain_engine()
|
||||
{
|
||||
local step_duration="$1"
|
||||
local base_color="$2"
|
||||
local mode="$3"
|
||||
local charset="$4"
|
||||
|
||||
command -v tput >/dev/null 2>&1 || {
|
||||
disp E "The program 'tput' is required but not installed."
|
||||
return 1
|
||||
}
|
||||
|
||||
do_exit() {
|
||||
_rain_build_colors "$base_color"
|
||||
_rain_build_chars "$mode" "$charset" || return 1
|
||||
|
||||
local rain_colors=("${RAIN_ENGINE_COLORS[@]}")
|
||||
local rain_chars=("${RAIN_ENGINE_CHARS[@]}")
|
||||
local rain_color_tab=${#rain_colors[@]}
|
||||
local rain_tab=${#rain_chars[@]}
|
||||
local matrix_head_color=$'\e[1;97m'
|
||||
|
||||
local exit_st=0
|
||||
local num_rain_metadata=5
|
||||
local term_height=0 term_width=0
|
||||
local X=0 Y=0 drop_length=0 rain_drop=0
|
||||
local max_rain_width=0 max_rain_height=0
|
||||
local new_rain_odd=0 falling_odd=0
|
||||
local term_area=0
|
||||
local frame_sleep="$step_duration"
|
||||
|
||||
sigwinch()
|
||||
{
|
||||
term_width=$(tput cols)
|
||||
term_height=$(tput lines)
|
||||
((term_area = term_width * term_height))
|
||||
|
||||
case "$mode" in
|
||||
matrix)
|
||||
((max_rain_width = term_area / 3))
|
||||
((max_rain_height = term_height < 8 ? 1 : term_height / 6))
|
||||
((new_rain_odd = term_height > 50 ? 100 : term_height * 2))
|
||||
((new_rain_odd = new_rain_odd * 85 / 100))
|
||||
((falling_odd = 100))
|
||||
|
||||
# Adapt cadence and density to terminal size for smoother rendering.
|
||||
if ((term_area < 1200)); then
|
||||
((max_rain_width = term_area / 4))
|
||||
frame_sleep=$(awk -v s="$step_duration" 'BEGIN { printf "%.3f", s * 1.15 }')
|
||||
elif ((term_area > 5000)); then
|
||||
((max_rain_width = term_area / 2))
|
||||
frame_sleep=$(awk -v s="$step_duration" 'BEGIN { printf "%.3f", s * 0.85 }')
|
||||
else
|
||||
frame_sleep="$step_duration"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
((max_rain_width = term_area / 4))
|
||||
((max_rain_height = term_height < 10 ? 1 : term_height / 10))
|
||||
((new_rain_odd = term_height > 50 ? 100 : term_height * 2))
|
||||
((new_rain_odd = new_rain_odd * 75 / 100))
|
||||
((falling_odd = term_height > 25 ? 100 : term_height * 4))
|
||||
((falling_odd = falling_odd * 90 / 100))
|
||||
frame_sleep="$step_duration"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
do_exit()
|
||||
{
|
||||
exit_st=1
|
||||
}
|
||||
|
||||
do_render() {
|
||||
# Clean screen first
|
||||
local idx=0
|
||||
do_render()
|
||||
{
|
||||
local idx=0 y=0 drop_color="" current_char="" render_color=""
|
||||
|
||||
for ((idx = 0; idx < num_rains * num_rain_metadata; idx += num_rain_metadata)); do
|
||||
X=${rains[idx]}
|
||||
Y=${rains[idx + 1]}
|
||||
drop_length=${rains[idx + 4]}
|
||||
for ((y = Y; y < Y + drop_length; y++)); do
|
||||
(( y < 1 || y > term_height )) && continue
|
||||
echo -ne "\e[${y};${X}H "
|
||||
((y < 1 || y > term_height)) && continue
|
||||
printf "\e[%d;%dH " "$y" "$X"
|
||||
done
|
||||
done
|
||||
|
||||
for ((idx = 0; idx < num_rains * num_rain_metadata; idx += num_rain_metadata)); do
|
||||
if (( 100 * RANDOM / 32768 < falling_odd )); then
|
||||
# Falling
|
||||
if (( ++rains[idx + 1] > term_height )); then
|
||||
# Out of screen, bye sweet <3
|
||||
rains=("${rains[@]:0:idx}"
|
||||
"${rains[@]:idx+num_rain_metadata:num_rains*num_rain_metadata}")
|
||||
(( num_rains-- ))
|
||||
if ((100 * RANDOM / 32768 < falling_odd)); then
|
||||
if ((++rains[idx + 1] > term_height)); then
|
||||
rains=("${rains[@]:0:idx}" "${rains[@]:idx+num_rain_metadata:num_rains*num_rain_metadata}")
|
||||
((num_rains--))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
X=${rains[idx]}
|
||||
Y=${rains[idx + 1]}
|
||||
rain_drop=${rains[idx + 2]}
|
||||
drop_color=${rains[idx + 3]}
|
||||
drop_length=${rains[idx + 4]}
|
||||
|
||||
for ((y = Y; y < Y + drop_length; y++)); do
|
||||
(( y < 1 || y > term_height )) && continue
|
||||
echo -ne "\e[${y};${X}H${drop_color}${rain_drop}"
|
||||
((y < 1 || y > term_height)) && continue
|
||||
if [[ "$mode" == "matrix" ]]; then
|
||||
current_char="${rain_chars[rain_tab * RANDOM / 32768]}"
|
||||
if ((y == Y + drop_length - 1)); then
|
||||
render_color="$matrix_head_color"
|
||||
else
|
||||
render_color="$drop_color"
|
||||
fi
|
||||
else
|
||||
current_char="$rain_drop"
|
||||
render_color="$drop_color"
|
||||
fi
|
||||
printf "\e[%d;%dH%b%s" "$y" "$X" "$render_color" "$current_char"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
trap do_exit TERM INT
|
||||
trap sigwinch WINCH
|
||||
# No echo stdin and hide the cursor
|
||||
stty -echo
|
||||
echo -ne "\e[?25l"
|
||||
printf "\e[?25l"
|
||||
printf "\e[2J"
|
||||
|
||||
echo -ne "\e[2J"
|
||||
local rains=()
|
||||
local num_rains=0
|
||||
local ch=""
|
||||
|
||||
sigwinch
|
||||
while (( exit_st <= 0 )); do
|
||||
if (( $exit_st <=0 )); then
|
||||
read -n 1 -t $step_duration ch
|
||||
case "$ch" in
|
||||
q|Q)
|
||||
do_exit
|
||||
while ((exit_st <= 0)); do
|
||||
read -r -n 1 -t "$frame_sleep" ch
|
||||
case "$ch" in
|
||||
q|Q)
|
||||
do_exit
|
||||
;;
|
||||
esac
|
||||
esac
|
||||
|
||||
if (( num_rains < max_rain_width )) && (( 100 * RANDOM / 32768 < new_rain_odd )); then
|
||||
# Need new |, 1-based
|
||||
rain_drop="${rain_cars[rain_tab * RANDOM / 32768]}"
|
||||
drop_color="${rain_colors[rain_color_tab * RANDOM / 32768]}"
|
||||
drop_length=$(( max_rain_height * RANDOM / 32768 + 1 ))
|
||||
X=$(( term_width * RANDOM / 32768 + 1 ))
|
||||
Y=$(( 1 - drop_length ))
|
||||
rains=( "${rains[@]}" "$X" "$Y" "$rain_drop" "$drop_color" "$drop_length" )
|
||||
(( num_rains++ ))
|
||||
fi
|
||||
|
||||
# Let rain fall!
|
||||
do_render
|
||||
if ((num_rains < max_rain_width)) && ((100 * RANDOM / 32768 < new_rain_odd)); then
|
||||
rain_drop="${rain_chars[rain_tab * RANDOM / 32768]}"
|
||||
drop_color="${rain_colors[rain_color_tab * RANDOM / 32768]}"
|
||||
drop_length=$((max_rain_height * RANDOM / 32768 + 1))
|
||||
X=$((term_width * RANDOM / 32768 + 1))
|
||||
Y=$((1 - drop_length))
|
||||
rains=("${rains[@]}" "$X" "$Y" "$rain_drop" "$drop_color" "$drop_length")
|
||||
((num_rains++))
|
||||
fi
|
||||
done
|
||||
echo -ne "\e[${term_height};1H\e[0K"
|
||||
|
||||
# Show cursor and echo stdin
|
||||
echo -ne "\e[?25h"
|
||||
do_render
|
||||
done
|
||||
|
||||
printf "\e[%d;1H\e[0K" "$term_height"
|
||||
printf "\e[?25h"
|
||||
stty echo
|
||||
unset exit_st
|
||||
trap - TERM INT
|
||||
trap - WINCH
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Let the rain fall (current style)
|
||||
# Usage: rain [OPTIONS]
|
||||
rain()
|
||||
{
|
||||
_rain_show_usage()
|
||||
{
|
||||
printf "Usage: rain [OPTIONS]\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-s, --speed NUM Set speed value (default: 5 => 0.050s).\n"
|
||||
printf "\t Values >=1 use a /100 scale (5 => 0.05s).\n"
|
||||
printf "\t Values <1 are interpreted as raw seconds.\n"
|
||||
printf "\t-c, --color COLOR Set the color theme (default: white).\n"
|
||||
printf "\t-h, --help Display this help message and exit.\n\n"
|
||||
printf "Available Colors:\n"
|
||||
printf "\t\e[32mgreen\e[0m\t: Matrix-like green shades\n"
|
||||
printf "\t\e[34mblue\e[0m\t: Deep ocean blue gradients\n"
|
||||
printf "\t\e[31mred\e[0m\t: Crimson/Blood rain\n"
|
||||
printf "\t\e[33myellow\e[0m\t: Amber and gold tones\n"
|
||||
printf "\t\e[36mcyan\e[0m\t: Electric cyan/turquoise\n"
|
||||
printf "\twhite\t: Greyscale and white (original style)\n\n"
|
||||
printf "Example: rain --color green --speed 3\n"
|
||||
}
|
||||
|
||||
local step_duration=0.050
|
||||
local base_color="white"
|
||||
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
-s|--speed)
|
||||
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
|
||||
step_duration=$(_rain_normalize_speed "$2") || {
|
||||
disp E "--speed requires a numeric value."
|
||||
_rain_show_usage
|
||||
return 1
|
||||
}
|
||||
shift
|
||||
else
|
||||
disp E "--speed requires a numeric value."
|
||||
_rain_show_usage
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
-c|--color)
|
||||
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
|
||||
base_color="$2"
|
||||
shift
|
||||
else
|
||||
disp E "--color requires a color name."
|
||||
_rain_show_usage
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
-h|--help)
|
||||
_rain_show_usage
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Unknown option: $1"
|
||||
_rain_show_usage
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
_rain_engine "$step_duration" "$base_color" "rain" ""
|
||||
}
|
||||
export -f rain
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Matrix style digital rain
|
||||
# Usage: matrix [OPTIONS]
|
||||
matrix()
|
||||
{
|
||||
_matrix_show_usage()
|
||||
{
|
||||
printf "Usage: matrix [OPTIONS]\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-s, --speed NUM Set speed value (default: 3.5 => 0.035s).\n"
|
||||
printf "\t Values >=1 use a /100 scale (3.5 => 0.035s).\n"
|
||||
printf "\t Values <1 are interpreted as raw seconds.\n"
|
||||
printf "\t-c, --color COLOR Set color theme (default: green).\n"
|
||||
printf "\t-C, --charset SET Character set: binary, kana, ascii (default: binary).\n"
|
||||
printf "\t-h, --help Display this help message and exit.\n\n"
|
||||
printf "Example: matrix -C kana -c green --speed 2\n"
|
||||
}
|
||||
|
||||
local step_duration=0.035
|
||||
local base_color="green"
|
||||
local charset="binary"
|
||||
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
-s|--speed)
|
||||
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
|
||||
step_duration=$(_rain_normalize_speed "$2") || {
|
||||
disp E "--speed requires a numeric value."
|
||||
_matrix_show_usage
|
||||
return 1
|
||||
}
|
||||
shift
|
||||
else
|
||||
disp E "--speed requires a numeric value."
|
||||
_matrix_show_usage
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
-c|--color)
|
||||
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
|
||||
case "${2,,}" in
|
||||
binary|kana|kanji|ascii)
|
||||
disp W "'${2}' looks like a charset value. Use -C/--charset for clarity."
|
||||
charset="${2,,}"
|
||||
;;
|
||||
*)
|
||||
base_color="$2"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
else
|
||||
disp E "--color requires a color name."
|
||||
_matrix_show_usage
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
-C|--charset)
|
||||
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
|
||||
charset="${2,,}"
|
||||
shift
|
||||
else
|
||||
disp E "--charset requires a value."
|
||||
_matrix_show_usage
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
-h|--help)
|
||||
_matrix_show_usage
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Unknown option: $1"
|
||||
_matrix_show_usage
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
_rain_engine "$step_duration" "$base_color" "matrix" "$charset"
|
||||
}
|
||||
export -f matrix
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# EOF
|
||||
|
||||
199
profile.d/ssh.sh
199
profile.d/ssh.sh
@@ -1,70 +1,159 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Remove host from know_host (name and IP) for the active user
|
||||
# ------------------------------------------------------------------------------
|
||||
rmhost ()
|
||||
# Usage: rmhost <hostname|ip> [hostname2|ip2 [...]]
|
||||
rmhost()
|
||||
{
|
||||
if [[ "$#" -lt 1 ]]; then
|
||||
echo "Error: incorrect number of parameters."
|
||||
echo "Usage: rmhost <hostname|ip> [hostname2|ip2 [...]]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
while [[ $1 ]]; do
|
||||
local hst=$1 && shift
|
||||
isipv4 $hst > /dev/null
|
||||
local v4=$?
|
||||
isipv6 $hst > /dev/null
|
||||
local v6=$?
|
||||
|
||||
if [[ $v4 -eq 0 || $v6 -eq 0 ]]; then
|
||||
local ip=$hst
|
||||
unset hst
|
||||
fi
|
||||
unset v4 v6
|
||||
|
||||
if [[ ! $ip && $hst ]]; then
|
||||
ip=$(host $hst | grep "has address" | awk '{print $NF}')
|
||||
[[ ! $? ]] &&
|
||||
echo "*** rmhost(): Error extracting IP from hostname." &&
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ $hst ]]; then
|
||||
echo "Removing host $hst from ssh known_host..."
|
||||
ssh-keygen -R $hst > /dev/null
|
||||
fi
|
||||
if [[ $ip ]]; then
|
||||
echo "Removing IP $ip from ssh known_host..."
|
||||
ssh-keygen -R $ip > /dev/null
|
||||
fi
|
||||
unset hst ip
|
||||
done
|
||||
}
|
||||
export -f rmhost
|
||||
local PARSED
|
||||
PARSED=$(getopt -o h --long help -n 'rmhost' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then return 1; fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Login root via SSH on the given machine
|
||||
# ------------------------------------------------------------------------------
|
||||
ssr ()
|
||||
{
|
||||
for opt in $@ ; do
|
||||
case $opt in
|
||||
"-h"|"--help")
|
||||
echo "ssr: do a root user ssh login."
|
||||
echo
|
||||
echo "Usage: ssr <server [ssh options]>"
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "rmhost: Remove host/IP from ~/.ssh/known_hosts.\n\n"
|
||||
printf "Usage: rmhost <hostname|ip> [hostname2|ip2 ...]\n\n"
|
||||
printf "Options:\n"
|
||||
printf " -h, --help Display this help screen\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"rmhost --help\" to display usage."
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ ! $1 ]] &&
|
||||
echo "Please specify the server you want to log in." &&
|
||||
# Validation: Ensure at least one argument remains
|
||||
if [[ $# -eq 0 ]]; then
|
||||
disp E "Missing argument. Use 'rmhost --help' for usage."
|
||||
return 1
|
||||
fi
|
||||
|
||||
for target in "$@"; do
|
||||
local hst=$target
|
||||
isipv4 "$hst" >/dev/null
|
||||
local v4=$?
|
||||
isipv6 "$hst" >/dev/null
|
||||
local v6=$?
|
||||
|
||||
if [[ $v4 -eq 0 || $v6 -eq 0 ]]; then
|
||||
local ip=$hst
|
||||
unset hst
|
||||
fi
|
||||
unset v4 v6
|
||||
|
||||
if [[ ! $ip && $hst ]]; then
|
||||
if ! ip=$(host "$hst" 2>/dev/null | awk '/has address/ {print $NF; exit}'); then
|
||||
disp E "Impossible to extract IP from hostname." &&
|
||||
return 1
|
||||
fi
|
||||
[[ -z $ip ]] && {
|
||||
disp E "Impossible to extract IP from hostname."
|
||||
return 1;
|
||||
}
|
||||
fi
|
||||
|
||||
if [[ $hst ]]; then
|
||||
disp I "Removing host $hst from ssh known_host..."
|
||||
ssh-keygen -R $hst >/dev/null
|
||||
fi
|
||||
if [[ $ip ]]; then
|
||||
disp I "Removing IP $ip from ssh known_host..."
|
||||
ssh-keygen -R $ip >/dev/null
|
||||
fi
|
||||
unset hst ip
|
||||
done
|
||||
}
|
||||
export -f rmhost
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Login root via SSH on the given machine
|
||||
# Usage: ssr <server [ssh options]>
|
||||
ssr()
|
||||
{
|
||||
local PARSED
|
||||
PARSED=$(getopt -o h --long help -n 'ssr' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then return 1; fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "ssr: SSH into a server as root.\n\n"
|
||||
printf "Usage: ssr <server> [ssh_options...]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"ssr --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
command -v ssh >/dev/null 2>&1 || {
|
||||
disp E "ssh is not installed."
|
||||
return 127
|
||||
}
|
||||
[[ ! $1 ]] && {
|
||||
disp E "Please specify the server you want to log in."
|
||||
return 1
|
||||
}
|
||||
|
||||
local srv=$1 && shift
|
||||
|
||||
ssh -Y root@$srv $@
|
||||
ssh -Y root@"$srv" "$@"
|
||||
}
|
||||
export -f ssr
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
192
profile.d/updates.sh
Normal file
192
profile.d/updates.sh
Normal file
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
# * with or without modification, are permitted provided
|
||||
# * that the following conditions are met:
|
||||
# *
|
||||
# * Redistributions of source code must retain the above
|
||||
# * copyright notice, this list of conditions and the
|
||||
# * following disclaimer.
|
||||
# *
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# * copyright notice, this list of conditions and the following
|
||||
# * disclaimer in the documentation and/or other materials
|
||||
# * provided with the distribution.
|
||||
# *
|
||||
# * Neither the name of the copyright holder nor the names
|
||||
# * of any other contributors may be used to endorse or
|
||||
# * promote products derived from this software without
|
||||
# * specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
export BASE_URL="https://git.geoffray-levasseur.org/fatalerrors/profile"
|
||||
export UPDT_URL="$BASE_URL/raw/branch/master"
|
||||
export ARCH_URL="$BASE_URL/archive/master.tar.gz"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Check for profile updates
|
||||
# Usage: check_updates [-q]
|
||||
# If -q is specified, the function will operate in quiet mode (internal use only)
|
||||
check_updates()
|
||||
{
|
||||
local quiet=0
|
||||
local PARSED=$(getopt -o hq --long help,quiet -n 'check_updates' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"check_updates --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "check_updates: Check for new versions.\n\n"
|
||||
printf "Usage: check_updates\n"
|
||||
return 0
|
||||
;;
|
||||
-q|--quiet)
|
||||
quiet=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
(( $quiet != 1 )) && disp I "Checking for updates..."
|
||||
local vfile="/tmp/version"
|
||||
wget "$UPDT_URL/version" -O $vfile >/dev/null 2>&1 || {
|
||||
disp E "Can't download version file, impossible to proceed!"
|
||||
return 5
|
||||
}
|
||||
|
||||
if [[ -s $vfile ]]; then
|
||||
local lastver=$(cat $vfile)
|
||||
if [[ $lastver != $PROFVERSION ]]; then
|
||||
disp I "You have version $PROFVERSION installed. Version $lastver is available."
|
||||
(( $quiet != 1 )) && disp I "You should upgrade to last version when possible."
|
||||
result=1
|
||||
else
|
||||
(( $quiet != 1 )) && disp I "Your version is up-to-date."
|
||||
result=0
|
||||
fi
|
||||
rm -f $vfile
|
||||
else
|
||||
disp E "Impossible to read temporary file, impossible to proceed."
|
||||
fi
|
||||
unset lastver vfile
|
||||
return $result
|
||||
}
|
||||
export -f check_updates
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Apply update to profile
|
||||
# Usage: profile_upgrade
|
||||
profile_upgrade()
|
||||
{
|
||||
local PARSED=$(getopt -o h --long help -n 'profile_upgrade' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
printf "Invalid options, use \"profile_upgrade --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "profile_upgrade: Upgrade the profile to the latest version.\n\n"
|
||||
printf "Usage: profile_upgrade\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"profile_upgrade --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if check_updates -q; then
|
||||
disp "No update available."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -s $MYPATH/profile.sh ]]; then
|
||||
disp E "Installation path detection failed, cannot upgrade automatically."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -d $MYPATH/.git ]]; then
|
||||
disp I "Git installation detected, applying git pull."
|
||||
pushd "$MYPATH" || {
|
||||
disp E "Failed to change directory to $MYPATH."
|
||||
return 3
|
||||
}
|
||||
git pull || {
|
||||
disp E "Git pull failed, upgrade not applyed."
|
||||
popd
|
||||
return 2
|
||||
}
|
||||
disp I "Successfully upgraded using git."
|
||||
popd
|
||||
else
|
||||
disp I "No Git detected. Downloading and applying upgrade from archive..."
|
||||
local tmpdir="/tmp/profile_upg.$$"
|
||||
mkdir -p "$tmpdir" || {
|
||||
disp E "Failed to create temporary directory."
|
||||
return 4
|
||||
}
|
||||
|
||||
local archive="$tmpdir/profile.tar.gz"
|
||||
wget -q "$ARCH_URL" -O "$archive" || {
|
||||
disp E "Failed to download archive."
|
||||
rm -rf "$tmpdir"
|
||||
return 5
|
||||
}
|
||||
|
||||
tar -xzf "$archive" -C "$tmpdir" || {
|
||||
disp E "Archive extraction failed."
|
||||
rm -rf "$tmpdir"
|
||||
return 6
|
||||
}
|
||||
|
||||
disp I "Installing new version..."
|
||||
cp -r "$tmpdir"/profile/* "$MYPATH"/ || {
|
||||
disp E "Failed to copy new files to $MYPATH."
|
||||
rm -rf "$tmpdir"
|
||||
return 7
|
||||
}
|
||||
|
||||
disp I "Upgrade complete. You should now logout and login again."
|
||||
rm -rf "$tmpdir"
|
||||
fi
|
||||
}
|
||||
export -f profile_upgrade
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# EOF
|
||||
260
profile.sh
260
profile.sh
@@ -1,42 +1,7 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Begin profile
|
||||
# ------------------------------------------------------------------------------
|
||||
# Initial version from Beyond Linux From Scratch by
|
||||
# * James Robertson <jameswrobertson@earthlink.net>
|
||||
# * Dagmar d'Surreal <rivyqntzne@pbzpnfg.arg>
|
||||
# ------------------------------------------------------------------------------
|
||||
# Current version from Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# 16/02/2013 v1.0.0 : Initial version
|
||||
# 24/10/2015 v2.0.0 : Added advanced functionnalities (clean, srr, etc.)
|
||||
# 04/02/2017 v2.0.1 : clean improvements (--shell)
|
||||
# 16/09/2018 v2.1.0 : Added rmhost, setc, setfr, more locales management
|
||||
# 23/09/2019 v2.1.1 : [bugfix] dpkgs
|
||||
# 24/09/2019 v2.1.2 : [bugfix] bug in profile version display
|
||||
# 16/12/2019 v2.2.0 : Added showinfo, primary write of showdiskmap
|
||||
# 08/01/2020 v2.3.0 : Added use of figlet and neofetch as a motd replace
|
||||
# 16/01/2020 v2.3.1 : [bugfix] non-interactive were blocked with some functions
|
||||
# 31/01/2020 v2.3.2 : Figlet: changed default font to ansi_shadow
|
||||
# 02/03/2020 v2.4.0 : Added command auzip
|
||||
# 03/03/2020 v2.5.0 : Added command taz and rmspc, auzip => utaz improved
|
||||
# 05/03/2020 v2.5.1 : Language consistancy fix, added pigz support in taz
|
||||
# 06/03/2020 v2.5.2 : Few aliases sorted out
|
||||
# 11/09/2020 v2.5.3 : Few more aliases, improved code consistancy and typo,
|
||||
# : improved utaz, removed showdiskmap, removed remaining French,
|
||||
# : added license information for future publication
|
||||
# 24/10/2020 v2.6.0 : Added session save and restore for Konsole
|
||||
# 25/12/2020 v2.6.1 : Add check on rmhost, improvements rmspc, created expendlist
|
||||
# 26/02/2021 v2.6.2 : [bugfix] taz: corrected bug with trailing slash on directories
|
||||
# 18/10/2021 v2.6.3 : changed PS1 for status bar style version, few minor improvements
|
||||
# 21/06/2022 v2.7.0 : added isipv4 and isipv6, use it in rmhost as an improvement
|
||||
# 22/06/2022 v2.7.1 : [bugfix] few minor corrections, added help command
|
||||
# 24/06/2022 v2.8.0 : Added backtrace, error and settrace, corrected showinfo
|
||||
# 19/07/2022 v2.8.1 : few cleanup, fixes and optimizations
|
||||
# 29/07/2022 v2.8.2 : added warning for non bash users
|
||||
# 27/08/2022 v3.0.0 : splitted everything, added rain screensaver
|
||||
# 07/11/2022 v3.0.1 : added concatenation to rmspc, added ku, error managed in meteo
|
||||
# 08/11/2022 v3.1.0 : added password generator
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright (c) 2013-2022 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
||||
# Protected by the BSD3 license. Please read bellow for details.
|
||||
#
|
||||
# * Redistribution and use in source and binary forms,
|
||||
@@ -70,46 +35,151 @@
|
||||
# * OF SUCH DAMAGE.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
export PROFVERSION="3.1.0"
|
||||
|
||||
export DEFAULT_CITY="Toulouse"
|
||||
|
||||
if [[ ! $(echo $SHELL | grep bash) ]]; then
|
||||
echo "That script is designed to be used with bash as being the shell."
|
||||
echo "Please consider using bash instead, or patch me ;) !"
|
||||
if [[ ! $SHELL =~ bash ]]; then
|
||||
echo "That environment script is designed to be used with bash being the shell."
|
||||
echo "Please consider using bash to enjoy our features!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Required for associative arrays (4.0+) and namerefs (4.3+)
|
||||
if ((BASH_VERSINFO[0] < 4)) || [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 3 ]]; then
|
||||
echo "[ Error ] This profile requires Bash 4.3 or higher."
|
||||
echo "Current version: $BASH_VERSION"
|
||||
return 1 2>/dev/null || exit 1
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# path* : private functions for PATH variable management
|
||||
# ------------------------------------------------------------------------------
|
||||
pathremove ()
|
||||
pathremove()
|
||||
{
|
||||
local ifs=':'
|
||||
local IFS=':'
|
||||
local newpath
|
||||
local dir
|
||||
local pathvar=${2:-PATH}
|
||||
for dir in ${!pathvar} ; do
|
||||
if [ "$dir" != "$1" ] ; then
|
||||
for dir in ${!pathvar}; do
|
||||
if [ "$dir" != "$1" ]; then
|
||||
newpath=${newpath:+$newpath:}$dir
|
||||
fi
|
||||
done
|
||||
export $pathvar="$newpath"
|
||||
}
|
||||
|
||||
pathprepend ()
|
||||
pathprepend()
|
||||
{
|
||||
pathremove $1 $2
|
||||
local pathvar=${2:-PATH}
|
||||
export $pathvar="$1${!pathvar:+:${!pathvar}}"
|
||||
}
|
||||
|
||||
pathappend ()
|
||||
pathappend()
|
||||
{
|
||||
pathremove $1 $2
|
||||
local pathvar=${2:-PATH}
|
||||
export $pathvar="${!pathvar:+${!pathvar}:}$1"
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Configuration file parser
|
||||
parse_conf()
|
||||
{
|
||||
local config_file="$1"
|
||||
local current_section=""
|
||||
local line key value
|
||||
|
||||
[[ ! -f "$config_file" ]] && return 1
|
||||
|
||||
while IFS='=' read -r key value || [[ -n "$key" ]]; do
|
||||
# Internal trimming (removes leading/trailing whitespace & CR)
|
||||
key="${key%"${key##*[![:space:]]}"}"
|
||||
key="${key#"${key%%[![:space:]]*}"}"
|
||||
key="${key%$'\r'}" # Strip potential Windows line endings
|
||||
|
||||
# Skip comments and empty lines
|
||||
[[ -z "$key" || "$key" =~ ^[#\;] ]] && continue
|
||||
|
||||
# Section Detection: [section_name]
|
||||
if [[ "$key" =~ ^\[([a-zA-Z0-9_]+)\]$ ]]; then
|
||||
current_section="${BASH_REMATCH[1]}"
|
||||
declare -g -A "CONF_$current_section"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Secure Assignment (if inside a section)
|
||||
if [[ -n "$current_section" ]]; then
|
||||
# Clean the value
|
||||
value="${value%"${value##*[![:space:]]}"}"
|
||||
value="${value#"${value%%[![:space:]]*}"}"
|
||||
value="${value%$'\r'}"
|
||||
|
||||
# Protect against command injection by disallowing certain characters in keys
|
||||
value="${value//\`/}"
|
||||
value="${value//\$\(/}"
|
||||
|
||||
# Correctly interpretet internal variables (e.g. $HOME)
|
||||
if [[ "$value" == *\$* ]]; then
|
||||
value=$(envsubst <<< "$value")
|
||||
fi
|
||||
|
||||
# Strip quotes (handling both " and ')
|
||||
value="${value%\"}"; value="${value#\"}"
|
||||
value="${value%\'}"; value="${value#\'}"
|
||||
|
||||
# Use a nameref for safe, eval-free assignment
|
||||
local -n current_array="CONF_$current_section"
|
||||
current_array["$key"]="$value"
|
||||
fi
|
||||
done < "$config_file"
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Load command aliases from configuration
|
||||
load_alias()
|
||||
{
|
||||
local section_name="CONF_$1"
|
||||
|
||||
# Check if the associative array exists using declare -p
|
||||
[[ "$(declare -p "$section_name" 2>/dev/null)" != "declare -A"* ]] && return 1
|
||||
|
||||
# Create a nameref to the section array
|
||||
local -n current_aliases="$section_name"
|
||||
|
||||
# Iterate safely over the keys of the associative array
|
||||
for key in "${!current_aliases[@]}"; do
|
||||
local cmd="${current_aliases[$key]}"
|
||||
|
||||
# Extract the base command (first word) safely without awk
|
||||
local base_cmd="${cmd%% *}"
|
||||
|
||||
# Only alias if the base command is executable
|
||||
if command -v "$base_cmd" >/dev/null 2>&1; then
|
||||
alias "$key"="$cmd"
|
||||
fi
|
||||
done
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Load configuration values as environment variables
|
||||
load_conf()
|
||||
{
|
||||
local section_name="CONF_$1"
|
||||
|
||||
[[ "$(declare -p "$section_name" 2>/dev/null)" != "declare -A"* ]] && return 1
|
||||
|
||||
local -n current_vars="$section_name"
|
||||
|
||||
for key in "${!current_vars[@]}"; do
|
||||
# Export the key/value pair as a standard shell variable
|
||||
# We use 'export' directly; Bash handles the assignment safely here
|
||||
export "$key"="${current_vars[$key]}"
|
||||
done
|
||||
}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -118,40 +188,43 @@ pathappend ()
|
||||
# ------------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Store script's path (realpath -s resolve symlinks if profile.sh is a symlink)
|
||||
# Because we're more likely to be sourced, we use BASH_SOURCE to get the path
|
||||
# of the sourced file instead of $0
|
||||
if [[ -z "$PROFILE_PATH" ]]; then
|
||||
export MYPATH=$(dirname "$(realpath -s "${BASH_SOURCE[0]}")")
|
||||
else
|
||||
export MYPATH="$PROFILE_PATH"
|
||||
fi
|
||||
if [[ ! -e "$MYPATH/profile.sh" ]]; then
|
||||
echo "[ Warning ] Path detection failed, trying to use pwd..."
|
||||
MYPATH=$(pwd)
|
||||
if [[ ! -e "$MYPATH/profile.sh" ]]; then
|
||||
echo "[ Error ] Impossible to determine installation path, pretty much nothing will work."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ! -s "$MYPATH/version" ]]; then
|
||||
echo "[ Warning ] Impossible to determine running version of profile, your installation might be broken."
|
||||
fi
|
||||
export PROFVERSION=$(cat "$MYPATH"/version)
|
||||
|
||||
# Build PATH environment variable
|
||||
if [[ $EUID -eq 0 ]] ; then
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
pathappend /sbin:/usr/sbin
|
||||
fi
|
||||
[[ -d /share/services/gestparc ]] && pathappend /share/services/gestparc
|
||||
[[ -d ~/bin ]] && pathappend ~/bin
|
||||
[[ -d ~/.local/bin ]] && pathappend ~/.local/bin
|
||||
|
||||
# Set bash history
|
||||
export HISTSIZE=50000
|
||||
export HISTIGNORE="&:[bf]g:exit"
|
||||
# Parse and load general configuration
|
||||
export PROFILE_CONF="$MYPATH/profile.conf"
|
||||
parse_conf "$PROFILE_CONF"
|
||||
load_conf system # Load Bash system behavior configuration (history, pager, etc.)
|
||||
load_conf general # General purpose configuration (compilation flags, etc.)
|
||||
|
||||
# Set default pager
|
||||
export PAGER=less
|
||||
|
||||
# More colors
|
||||
export TERM=xterm-256color
|
||||
|
||||
# Set some compiling values
|
||||
export CFLAGS="-O2 -pipe -march=native"
|
||||
export MAKEFLAGS='-j12'
|
||||
export PKGSOURCES='/share/src/archives'
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Default values could be altered after this line
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Load personal configuration
|
||||
[[ -f ~/.profile.conf ]] && . ~/.profile.conf
|
||||
|
||||
# Execute optionnal config script if any
|
||||
for script in ~/profile.d/*.sh ; do
|
||||
if [ -r $script ] ; then
|
||||
# Load module scripts
|
||||
for script in $MYPATH/profile.d/*.sh; do
|
||||
if [[ -r $script ]]; then
|
||||
. $script
|
||||
fi
|
||||
done
|
||||
@@ -159,34 +232,12 @@ done
|
||||
# Interactive shell detection, two methods available each one of those might have different result
|
||||
# depending on distribution
|
||||
#shopt -q login_shell && INTERACTIVE=1
|
||||
[[ $- == *i* ]] && INTERACTIVE=1
|
||||
[[ $- == *i* ]] && export INTERACTIVE=1
|
||||
|
||||
if [[ $INTERACTIVE ]]; then
|
||||
# For compiling (as we often compile with LFS/0linux...)
|
||||
#Aliases
|
||||
alias ll='ls -laFh --color=auto'
|
||||
alias la='ls -Ah --color=auto'
|
||||
alias l='ls -CF --color=auto'
|
||||
alias ls='ls --color=auto'
|
||||
|
||||
alias grep='grep --color=auto'
|
||||
alias egrep='egrep --color=auto'
|
||||
alias fgrep='fgrep --color=auto'
|
||||
alias qfind="find . -name "
|
||||
|
||||
alias mkck='make check'
|
||||
alias mkin='make install'
|
||||
alias mkdin='make DESTDIR=$PWD/dest-install install'
|
||||
alias ssh='ssh -Y'
|
||||
|
||||
alias wget='wget -c' # resume mode by default
|
||||
alias myip='curl ip.appspot.com'
|
||||
|
||||
# Human readable by default
|
||||
alias df='df -H'
|
||||
alias du='du -ch'
|
||||
|
||||
alias sdu='du -sk ./* | sort -n'
|
||||
load_alias aliases
|
||||
|
||||
# Define PS1
|
||||
trap 'timer_start' DEBUG
|
||||
@@ -194,8 +245,9 @@ if [[ $INTERACTIVE ]]; then
|
||||
|
||||
# Set default language
|
||||
setfr
|
||||
showinfo
|
||||
echo "Profile version $PROFVERSION chargé..."
|
||||
showinfo && printf "\n"
|
||||
check_updates -q
|
||||
disp I "Profile version $PROFVERSION chargé..."
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
|
||||
Reference in New Issue
Block a user