Newsgroup: it.comp.os.linux.iniziare
Titolo: creare un wrapper script

$ cat ~/bin/rsync
#!/usr/bin/env bash
# fai qualcosa
/usr/bin/rsync
# fai qualcos'altro
 
Ma siamo sicuri che il file originale si trovi in /usr/bin?
Sul mio computer si può dedurre che la posizione è standard:
 
$ echo $PATH
~/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
 
o ancora meglio
 
$ whereis rsync
rsync: /usr/bin/rsync ~/bin/rsync
 
Ma su un altro sistema non si può sapere...
In pratica dal $PATH vorrei scartare la posizione del wrapper-script 
(~/bin) in modo che la ricerca venga fatta sugli altri path 
(/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin).
Si può?


In due parole:
Da $PATH deve essere escluso $(dirname "$0")


Basta ridefinire PATH all'interno dello script o anche solo per la 
ricerca e trovare dove realmente sia.
RSYNC=$(PATH="/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/local/games:/snap/bin" 
which rsync)
 
La variabile RSYNC conterrà il path "/usr/bin/rsync" cioè la prima 
occorrenza di rsync nel path di ricerca disponibile a "which".
 
Per un normale utente sarebbe preferibile che la variabile PATH 
contenesse solo le directory di normale pertinenza.
 
Ciao
Giovanni
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   < 
http://giovanni.homelinux.net/
 >


Non so se è questo che intendi...
Ho copiato per esempio l'eseguibile echo da /bin a /usr/games
 
echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
 
$ which -a echo
/bin/echo
/usr/games/echo
 
which -a echo | grep -v "/bin"
/usr/games/echo
 
$(which -a echo | grep -v "/bin") "pippo"
pippo
 
 
Controprova, cancello /usr/games/echo
 
$(which -a echo | grep -v "/bin") "pippo"
bash: pippo: command not found
 
Adesso faccio il grep su una directory dove sono sicuro non ci sia "echo"
 
$(which -a echo | grep -v "/usr") "pippo"
pippo
 
Infatti:
which -a echo | grep -v "/usr"
/bin/echo
 
 
-- 
The future is wonderful, the future is terrifying.
The future? But will we still be there?

 contenesse solo le directory di normale pertinenza.
 
????


e se nel path ad es. ci fosse anche /bin2 ?


Se il wrapper _é_ in /bin2, usi /bin2
 
Comunque:
 
cat lista ; echo "----" ; cat lista | grep -v "^/bin$"
/usr/local/bin
/usr/bin
/bin
/usr/local/games
/usr/games
/bin2
/usr/local/bin2
 
----
/usr/local/bin
/usr/bin
/usr/local/games
/usr/games
/bin2
/usr/local/bin2
 
 
 
 
 
 
cat lista ; echo "----" ; cat lista | grep -v "^/usr/local$"
/usr/local/bin
/usr/bin
/bin
/usr/local/games
/usr/games
/bin2
/usr/local/bin2
 
----
/usr/local/bin
/usr/bin
/bin
/usr/local/games
/usr/games
/bin2
/usr/local/bin2
 
Nessun /usr/local e basta!
 
 
Eppoi... Uffa, non credo che una distribuzione metta rsync in un posto balordo come /usr/pippo/balengo/9⅜  !!!


 ????
 
Le directory /usr/local/sbin, /usr/sbin e /sbin dovrebbero essere solo 
nel path dell'utente root perché dovrebbero contenere solo comandi 
eseguibili dall'utente root.  Per sicurezza è sbagliato che un utente 
esegua quei comandi se non esplicitamente richiamati col path completo.



Ma scusa, fammi capire, ci sono due "rsync"?
Uno da dove lo lanci, cioe` $(dirname "$0"),
ed un altro in /usr/bin?
 
Oppure chiami "/usr/bin/rsync" ricorsivamente?
 
bye,
 
-- 
 
piergiorgio

 Eppoi... Uffa, non credo che una distribuzione metta rsync in un posto balordo come /usr/pippo/balengo/9⅜  !!!
 
E quindi?
E poi rsync è solo un esempio.
Potrei ad es. voler overridare ~/bin/abc con /usr/local/bin/abc o viceversa.

 Oppure chiami "/usr/bin/rsync" ricorsivamente?
 
$ cat ~/bin/rsync
#!/usr/bin/env bash
# fai qualcosa
/usr/bin/rsync
# fai qualcos'altro
 
I post iniziali andrebbero letti :)

 
 
boh, cmq non vedo perchè dovrei ridefinire il path

 rsync: /usr/bin/rsync ~/bin/rsync
 
OK.
 
E perche` hai due programmi diversi con nomi uguali?
 
Non e` meglio avere nomi diversi... Ed unici...?
 
bye,
 
-- 
 
piergiorgio


certo che a frullate mentali sei grande :)
 
imposti nello script un PATH std e sei a posto

 Non e` meglio avere nomi diversi... Ed unici...?
 
Overriding?

 imposti nello script un PATH std e sei a posto
 
E quale sarebbe?

 Overriding?
 
Eh?
 
E per quale motivo uno vorrebbe fare questo?
 
Voglio dire, di solito si fa l'opposto, si cerca
di evitare queste situazioni...
 
bye,
 
-- 
 
piergiorgio


su -
echo $PATH
 
 
dovrebbe essere /bin:/usr/bin:/usr/local/bin
togliendo gli sbin che sono dir per amministrare il sistema
 
 
 

 di evitare queste situazioni...
 
mettiamo che rsync venga richiamato da alcuni script insicuri (da testare).
per sicurezza mi creo
 
~/bin/rsync
 
 
#!/bin/bash
set -uex
#qualcosa
/usr/bin/rsync \
	-n \
	"$@"
#qualcosaltro
echo "NOTA: simulazione terminata"

 dovrebbe essere /bin:/usr/bin:/usr/local/bin
 
dovrebbe...
 

 per sicurezza mi creo
 
Crei "rsync_test.sh" e cambi la chiamata nello script.
 
Quando hai finito il testing, rimetti "rsync" standard.
 
Cosi` sei *veramente* sicuro che non venga chiamato
il "rsync" ufficiale, finche` non sei sufficientemente
certo che l'operazione sia corretta.
 
D'altro canto, se il problema e` in testing di script, si
dovrebbe, forse, procedere in maniera piu` sistematica.
 
E, per prima cosa, evitare script troppo convoluti, dato
che sono esponenzialmente piu` difficili da verificare.
 
bye,
 
-- 
 
piergiorgio

 Crei "rsync_test.sh" e cambi la chiamata nello script.
 
Per dire, si potrebbe, volendo, avere cose come:
 
if [ debug ]
  rsync_debug.sh
else
  rsync
fi
 
Un po' barocco, per uno script, ma se proprio uno
volesse e` anche possibile.
 
bye,
 
-- 
 
piergiorgio


mai sentito parlare del 'FHS'?
 
https://it.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
 
https://www.thegeekstuff.com/2010/09/linux-file-system-structure
 


 volesse e` anche possibile.
 
E con script di terze parti?
E se volessi fare ad es. un logging dell'output di rsync, o mille altre 
cose (mocking, simulazioni, reindirizzamento delle directory...) non è 
meglio avere un hook centralizzato, senza intaccare gli altri script.
 
Se ad es. voglio disattivare rsync, ecco qua:
 
#!/bin/bash
echo rsync disattivato
# /usr/local/bin/rsync "$@"

 
https://www.thegeekstuff.com/2010/09/linux-file-system-structure
 
 
Ho tre rsync:
 
/usr/bin/rsync
/home/io/bin/rsync
/home/io/bin-debug/rsync
 
Ho questo $PATH:
 
/home/io/bin-debug:/home/io/bin:/urs/bin
 
Quando lancio /home/io/bin-debug/rsync però voglio che venga rispettata 
la priorità dei path, escludendo naturalmente il self-path 
(/home/io/bin-debug).
 
Quindi deve essere lanciato /home/io/bin/rsync e non /usr/bin/rsync.
Come dici tu, la priorità dei path non verrebbe rispettata.

 # /usr/local/bin/rsync "$@"
 
Eh?
 
E non devi modificare un file comunque?
 
Se voglio disattivare "rsync" metto un "getopt",
con l'opzione "--norsync", nello script.
E poi uso "if ... else" od altre soluzioni.
 
Se sparpagli cose in giro per script rischi di
perdere il controllo di quello che succede.
Cambi l'hook ed un altro script non funziona piu`,
vai poi a vedere perche`...
 
bye,
 
-- 
 
piergiorgio

 di tutta una serie di *altri* script.
 
Il punto e`, se l'hook centralizzato contiene una serie
di funzioni che vengono usate per fare qualcosa, il tutto
e` abbastanza regolare.
 
Se l'hook centralizzato, invece, ha lo scopo di modificare
a cascata il comportamento di altri script, allora, a mio
avviso, il gioco non vale la candela.
 
Ogni modifica comportamentale dovrebbe essere il piu`
locale possibile, in modo da evitare di propagare le
modifiche in maniera incontrollata.
 
Se cambi l'hook centralizzato *devi* tener presente che
tutto quello che lo usa ne subira` le conseguenze.
 
bye,
 
-- 
 
piergiorgio


io imposterei un path personalizzato nello script
Comunque:
 
PATH=$(echo "$PATH" | sed -e 's@/home/l/svn/ams/bin:@@')
 
elimina /home/l/svn/ams/bin da PATH
basta metterlo nello script
 
 

 
 
Non posso testarlo adesso, ma mi sembra una buona soluzione.

 vai poi a vedere perche`...
 
E secondo te mi metto a fare cambiamenti in modo inconsapevole?

 tutto quello che lo usa ne subira` le conseguenze.
 
Si, si, si, ok, ok, ok, è chiarissimo.
Non l'ho ripetere più ;)

 RSYNC=$(PATH="/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/local/games:/snap/bin" which rsync)
con un path statico come definito a livello di sistema e dove 
sicuramente troverai i comendi si sistema.
 
3)  se proprio vuoi fare uno script con lo stesso nome del comando di 
sistema all'interno del script metti il path completo (p.e. 
/usr/bin/rsync nel caso che tu hai posto).  Dove si trova rsync lo devi 
scoprire ma se è un comando standard sicuramente in tutte le 
distribuzioni si troverà in una delle directory di sistema.
 
4)  possono esserci altre soluzioni ma sicuramente devono rispondere ad 
uno dei criteri precedentemente esposti.


 E secondo te mi metto a fare cambiamenti in modo inconsapevole?
 
Mi sorge il dubbio!
 
Vedi post scritto pochi minuti fa.
Se stai facendo test lo chiami in modo diverso dal comando di sistema 
proprio per distinguerlo e, se lo vuoi mettere di sistema, ci sono modi 
per renderlo disponibile in modo che non interferisca col comando originale.


 solo aggiungere funzionalità accessorie (non dannose).
 
Tu scrivi che cambi tale script per fare una cosa
oppure un'altra.
 
Questo non e` "aggiungere funzionalita` accessorie",
perche` se cosi` fosse basterebbe dare allo script
un nome diverso.
 
Queste sono modifiche comportamentali di, nel caso
portato ad esempio, "rsync".
 
Altrimenti avresti "rsync", in /usr/bin, e qualcosa
come "myrsync.sh", oppure "rsync_extended.sh", in
/usr/local/bin.
 
E poi, l'utente, potrebbe scegliere quale usare, a
seconda dello scopo dello script.
 
bye,
 
-- 
 
piergiorgio

 E roba che servirà solo in fase di sviluppo, come avrai capito.
 
Come scritto sopra, devi deciderti.
 
Se serve in fase di sviluppo, lanci un "bash" con
PATH assegnato, per esempio, in ~/support/bin, al
posto del PATH originale, e fai tutti i test che vuoi.
 
Che sarebbe un mini-environment, riproducibile in
vari modi, vedi docker, oppure macchine virtuali.
 
Dipende da quello che vuoi.
 
Quindi, il tuo problema, non e` "creare un wrapper
script" come da titolo thread, bensi` come fare il
testing di script.
 
Non era meglio far partire il thread con la domanda
giusta, invece di chiedere come mai la tua soluzione
non funziona?
 
bye,
 
-- 
 
piergiorgio

 posto del PATH originale, e fai tutti i test che vuoi.
 
O meglio, *prima* del PATH originale.
 
Quindi, qualcosa come, lanci "bash" (da bash)
e poi fai un "source myenv.sh" che contiene:
 
PATH=<mypath>:$PATH
 
Stando attenti che tutto quello che non
e` in <mypath>, viene da $PATH.
 
Quando hai finito il testing, esci da "bash
(c'e` l'altra sotto).
 
Il che mi pare il modo piu` semplice ed anche
piu` standard, per fare testing di script (nel
caso in cui si vogliano sabotare programmi
esterni, chiaramente).
 
bye,
 
-- 
 
piergiorgio


Tu sei stato ben piu esaustivo di me,in pratica approvo perfettamente il 
tuo scritto
Si spera che l'amico tragga lezione da chi e' piu esperto di lui
 

 seconda dello scopo dello script.
 
Fammi capire.
 
Modifiche comportamentali:
bisogna dare un nome diverso allo script o no?
 
Funzionalità aggiunte:
bisogna dare un nome diverso allo script o no?
 
 

 non funziona?
 
Certo, per certi versi, le tue considerazioni non sono sbagliate.
Valuterò!!!

 e` in <mypath>, viene da $PATH.
 
????????????????????
:-DDDDDDDD
Solita *espressione criptica*.

 distribuzioni si troverà in una delle directory di sistema.
 
????

 ????
 
Non c'è peggior sordo di chi non vuol sentire :-(
 
Ma che vieni a chiedere sul NG se poi non vuoi accettare quello che ti 
si risponde?


 occorrenza di rsync nel path di ricerca disponibile a "which".
 
E questa complessità aggiuntiva a cosa gli servirebbe?

 che, sostanzialmente, sono quello che vuoi fare tu.
 
Questo però è in disaccordo con quanto avevi detto.
 
"Come fai a sapere se lo script chiama "rsync",



Non mi pare sia in disaccordo.
 
Dove vedi cio`?
 
bye,
 
-- 
 
piergiorgio


Dovrebbe servire a ricavare il path name di rsync nel caso non sia 
conosciuto e senza modificare PATH a livello di script.
La modifica di PATH è valida solo per l'esecuzione di which.
 
Quanto al motivo per cui voglia chiamare con lo stesso nome due comandi 
diversi lo dovresti chiedere ad alex.


 Dove vedi cio`?
 
Lo standard che tu citi in definitiva quale sarebbe?
 
1. usare il path assoluto (/usr/bin/rsync)
2. affidarsi al PATH (e usare semplicemente *rsync*)
3. modificare il PATH preventivamente (perchè?) e quindi tornare al punto 2

 diversi lo dovresti chiedere ad alex.
 
Forse per creare una versione personalizzata di rsync, sfruttando il 
principio di astrazione (facade).


Si, ma dovrebbe accettare, se vuole chiamare il comando di sistema senza 
cablare direttamente il path completo, che deve fornire al sistema un 
PATH che escluda la dir dove ha messo il comando modificato.



Non "cito" nessun standard.
 
Quello che scrivo e` che per poter fare una
sostituzione (di "rsync", in questo esempio),
si deve andare a vedere come lo script chiami
il comando, dato che nei casi 1. e 3. non e`
cosi` banale far eseguire un "rsync" sostitutivo.
 
Nota che da 3. non torni a 2., sono cose diverse.
 
In 2. ci si affida al PATH esportato verso lo
script, in 3. lo script stesso modifica il PATH,
rendendo *inutile* il PATH esportato (da chi
chiama lo script).
 
Ulteriormente, il fatto e` che "in certi tipi di
script", e` normale (standard) fare 1. o 3., per
evitare proprio che il comando possa essere diverso
da quello che si vuole.
 
Solo che 3. e` piu` comodo, dato che consente di
scrivere lo script senza dover far precedere ogni
comando dal percorso completo.
 
Ad esempio, supponiamo che PATH=/home/pippo/bin:/usr/bin
 
Chiamando "rsync" direttamente, si cerca prima nel
folder "bin" dell'utente "pippo", poi nel folder
"/usr/bin" di sistema.
 
Se nello script c'e`:
 
PATH=/usr/bin
...
rsync
 
Il comando viene cercato solo nel folder di sistema
e *mai* in quello dell'utente.
Proprio per evitare che si possa eseguire un comando
omonimo, creato dall'utente per qualche motivo.
 
Questa pratica e` "standard", nel senso che e` comune,
in molti script di sistema.
 
bye,
 
-- 
 
piergiorgio


Sicuramente il mio approccio, per certi versi, è da rivedere.
Cmq hai colto esattamente il concetto.

 in molti script di sistema.
 
Cosa intendi esattamente con script di sistema?
Comunque in pratica tu sconsigli di fare affidamento sul PATH esportato?

 Comunque in pratica tu sconsigli di fare affidamento sul PATH esportato?
 
Dipende da cosa si deve fare, non c'e` una regola
generale ed assoluta.
 
Se si ha uno script che, per esempio, riordina file,
magari non e` necessario specificare dove siano i
vari comandi.
Forse e` sufficiente affidarsi al fatto che questi
comandi esistano da qualche parte raggiungibile in
condizioni normali.
 
D'altro canto, se abbiamo uno script piu` delicato,
magari che viene eseguito con privilegi elevati
(root o simili), forse conviene essere sicuri che i
vari comandi siano proprio quelli che ci si aspetta
e niente di piu`.
Quindi si ri-definisce PATH in modo appropriato.
 
Infine, puo` proprio essere che sia necessario usare
PATH esportato dal chiamante, cioe` che si debba
evitare di cambiare la ricerca degli eseguibili nello
script stesso.
Proprio perche` ci si aspetta che tale ricerca sia
coordinata dal chiamante.
 
Insomma, dipende caso per caso.
Bisogna capire cosa si stia facendo.
 
bye,
 
-- 
 
piergiorgio

 coordinata dal chiamante.
 
Forse l'esigenza dell'OP era proprio questa.

 Forse l'esigenza dell'OP era proprio questa.
 
Non saprei, ma questo caso riguarda la situazione in
cui, per esempio, vi e` una serie di script, magari
anche chiamati uno d'altro, e si vuole evitare qualche
interferenza, cambiando arbitrariamente variabili, o
anche altro, definite esternamente.
 
Dicevo, non saprei se questo e` il caso dell'OP, ma
avere un wrapper e` proprio una violazione di questa
esigenza.
 
bye,
 
-- 
 
piergiorgio


faccio solo  notare che gli script non possono essere suid (per un buon 
motivo)
Comunque per uno script che deve eseguire comandi std imposterei nello 
script un path std
Senza farsi troppe seghe mentali al contrario dell' amico che ha 
originato tutto il dibattito.

 motivo)
 
suid?

 originato tutto il dibattito.
 
Esatto.
 
bye,
 
-- 
 
piergiorgio

 
 
prende la variabile secure_path definita in /etc/sudoers



si,proprio suid
 


tradotto in madrelingua (le lingue straniere non sono mai state la mia 
passione)?


E' una specie di permesso speciale
(Set User IDentification)
 
http://www.linuxguide.it/linux/amministrazione_sistema/permessi/229_Permessi-speciali.html
 
 
bye
 
-- 
"Non esiste alcun dio, ma non ditelo al mio domestico,
se no di notte viene ad uccidermi."  - Voltaire