Des Astuces shell pour MAC/OSX mais valables pour UNIX et LINUX.

Grand merci à KLAUS !

à la page précédente.

TABLE des MATIÈRES :

Commandes utiles

Planification 2

Utilitaires Internet

Utilitaires Internet 2

Asuces Shell 2

Tuer !

Astuces Apache

Les commandes intégrées au Shell

Démarrage du Shell 'tcsh'

'find' et 'xargs'

L'Editeur de Texte Vim

Comment faire pour...?

Comment faire pour...?

L'Editeur de Texte Vim - II

tcsh vs sh/bash

Gérer les fichiers tenaces

Astuces sur le Scripting

Liens at Alias (6 Octobre

Astuces d'Edition

Expressions Régulières POSIX

Expressions Régulières POSIX II

Logging

Gestion Avancée du Logging

ftp (1

ntenance Périodique

Astuces de Scripting du Bash

Astuces Bash

La commande 'open' 

Extension des Paramètres Bash

Editeur Vim III - Rechercher

Type de Fichier de part son Contenu

Personnalisation du Shell Bash

Documents Céans sous Bash

Scripts Utiles

Le Terminal de Panther

Commandes plutôt cool

Tirer le Meilleur de Bash - I

Tirer le meilleur de Bash - II

Elle Vend des Sous-shell Entre Parenthèses

NetInfo

Signaux et Trappes

Contrôle des Tâches 

Conditions sous Bash

Guillemets et Apostrophes sous Bash

Montages AFP et NFS

L'Editeur de Flux sed

Le Processeur Awk

Awk Avancé

ntenance Fichiers

Comportements Bizarres dans...

Comptes Utilisateur 

Astuces de Script Bash III

Astuces de Script Bash IV 

Régler FTP

Quelques Commandes Utiles

Comptes Utilisateur II

Trouve

Espaces dans les Noms de Fichier 

Astuces Terminal

En Cas de Problèmes

Référence des Commandes Unix

Référence des Commandes Unix II

Référence des Commandes Unix III

Référence des Commandes Unix IV

Contrôler Bash au Démarrage

Nouveautés de Tiger

Séparater les composants d'un nom de fichier

Utilisez la technique suivante dans des scripts tsch pour extraire d'une variable ou d'un paramètre les composants d'un chemin d'accès complet à un fichier.

Le chemin d'accès complet :

% echo $fn
/Users/saruman/Documents/Essentials/todo.rtf

Extrayez le chemin d'accès (en-tête) :

% echo $fn:h
/Users/saruman/Documents/Essentials

Extrayez le nom de fichier (queue):

% echo $fn:t
todo.rtf

Extrayez l'extension :

% echo $fn:e
rtf

Retirez l'extension :

% echo $fn:r
/Users/saruman/Documents/Essentials/todo

Séparer les composants d'un nom de fichier II

Suite de l'astuce de Lundi, les modifieurs ':' peuvent être combinés. Pour juste extraire le nom de fichier sans l'extension, combinez t et r :

% echo $fn
/Users/saruman/Documents/Essentials/todo.rtf

% echo $fn:t:r
todo

Vous pouvez changer un nom de fichier en utilisant une substitution :

% echo $fn
/Users/saruman/Documents/Essentials/todo.rtf

% echo $fn:t:s/.rtf/.txt/
todo.txt

Batch Rename

Mac OS X n'a pas de commande permettant de renommer plusieurs fichiers. Utilisez les techniques de Lundi et de Mardi pour écrire un script qui le fera.

% cat rename
#!/bin/tcsh
set fn_new={$1:r}.$2
echo rename $1 $fn_new
mv $1 $fn_new

Ajoutez la commande 'find' des semaines 1 et 13 pour renommer en mode batch (arrière-plan) :

% ls
a.htm b.htm c.htm

% find . -name "*.htm" -exec rename {} html ;
rename ./a.htm ./a.html
rename ./b.htm ./b.html
rename ./c.htm ./c.html

% ls
a.html b.html c.html

Extraction sur la Ligne de Commande

Les techniques de Lundi et Mardi peuvent être appliquées aux commandes tcsh tapées sur la ligne de commande. En particuliers, elles peuvent être combinées avec l'astuce du Vendredi de la semaine 29 :

% ls *.html
a.html b.html c.html

% ls !*:r
ls *
a.html b.html c.html rename rename2

et

% ls *.htm
ls: No match.

% ls !*:r.html
ls *.html
a.html b.html c.html

Je vous laisserai deviner ce qui va arriver.


basename et dirname

Les commandes basename et dirname extraient les parties respectives d'un nom de chemin complet. Ce sont des commandes et elles peuvent donc être utilisées dans n'importe quel script, au contraire des astuces du début de la semaine qui sont spécifiques à tcsh.

% echo $fn
/Users/saruman/Documents/Essentials/todo.rtf

% echo `basename $fn`
todo.rtf

% echo `dirname $fn`
/Users/saruman/Documents/Essentials

'find' étendu

Certaines personnes ont quelques fois besoin d'appliquer la même commande à plusieurs fichiers et l'utilisation de 'find' est une bonne approche. Vous pouvez écrire le script suivant pour rendre la chose plus simple.

% cat xfind

#!/bin/sh if [ "$1" = " ]; then echo "Usage: `basename $0` filetype [command to -exec]" exit fi
if [ "$2" = " ]; then find . -name "$1" else find . -name "$1" -exec $2 {} ; fi

Ce script est écrit en /bin/sh, plutôt qu'en /bin/tcsh. N'oubliez pas de rendre le fichier script exécutable.

% xfind "*.html"

va lister tous les fichiers correspondants du répertoire courant et des sous-répertoires.

% xfind "*.html" less

va les afficher.


De Mac vers Unix

Voici un script pour changer un fichier comportant des caractères de fin de ligne traditionnels Mac en un fichier comportant des fins de lignes Unix.

% cat unix2mac

#!/bin/sh
if [ "$1" = " ]; then echo "Usage: `basename $0` filename" exit fi
tr \r \n < $1 > $1.tmp ; mv $1.tmp $1

Ce script peut être combiné avec le script xfind de Lundi :

% xfind "*.html" unix2mac

De Unix vers Mac

Pour compléter le script de Mardi, voici l'opération inverse :

% cat mac2unix

#!/bin/sh

if [ "$1" = " ]; then echo "Usage: `basename $0` filename" exit fi
tr \n \r < $1 > $1.tmp ; mv $1.tmp $1

Batch Rename

Voici un script pour renommer des fichiers dans le répertoire courant. Il peut être adapté pour effectuer d'autres fonctions.

% cat rename

#!/bin/sh #Je vous laisserai le soin de tester les erreurs...
for fn in *.$1 do mv $fn `basename $fn $1`$2 done

La commande :

% rename txt rtf

va changer *.txt en *.rtf dans le répertoire courant.


Utiliser les apostrophes

N'oubliez pas que quand vous insérez une commande dans des apostrophes, vous pouvez utiliser ses sorties comme des arguments pour une autre commande.

Par exemple, pour éditer tous les fichiers html dans un répertoire et ses sous-répertoires (en utilisant le script 'xfind' de lundi) :

% vi `xfind "*.html"`

(ou vim, emacs, pico, bbedit...)


Activer 'at'

La commande Unix 'at' peut être utilisée pour executer une commande donnée à une heure donnée. (Mais pas à une date donnée dans OS X). Toutefois, quelques modifications doivent être faites à OS X avant que ce ne soit possible. Celles-ci doivent être faites en tant que root.

1. Enlevez les signes de commentaires (les #) dans la ligne suivante qui est dans /etc/crontab:

#*/5 * * * * root /usr/libexec/atrun

pour vérifier les jobs 'at' en attente toutes les 5 minutes.

2. Créez le répertoire suivant s'il n'existe pas encore :

sudo mkdir /var/at/spool

3. Créez un fichier 'deny' vide pour permettre à tous les utilisateurs d'utiliser 'at'

sudo touch /var/at/at.deny

(Ou créez 'at.allow' et ajoutez une liste des utilisateurs ayant l'autorisation.)

(Voir la semaine 33 pour plus de commandes de planification.)


Utiliser 'at'

Utilisez la commande 'at' pour programmer une (suite de) commande(s) à executer plus tard. L'exemple suivant programme le déclenchement de l'application Horloge à 21:30 aujourd'hui. Les commandes à exécuter peuvent être directement fournies sur la ligne de commande, ou lues d'un fichier avec l'option '-f'.

% cat at-file
open /Applications/Clock.app

% at -f at-file 21:30
Job a010b400a.000 will be executed using /bin/sh

A 21:30, l'application Horloge de OS X sera lancée.


'atq' et 'atrm'

Il est possible d'examiner la liste des jobs dans la queue 'at' de l'utilisateur du moment avec :

% atq
Date                    Owner   Queue   Job#
21:26:00 04/20/03       saruman a       a010b400a.000

et effacer des jobs avec :

% atrm a010b400a.000

en donnant le numéro du job qui est plutôt vilain.


Plus sur 'at'

Quand la liste des commandes donnée par 'at' est éxécutée, elle l'est par le shell /bin/sh. Les variables d'environnement et le répertoire actuel sont recréés pour correspondre à ceux qui existaient quand la commande 'at a été lancée.

Si des commandes doivent se reporter à votre répertoire de base, utilisez :

$HOME

Le temps peut être spécifié par rapport à l'instant présent avec :

at -f at-file now + 10 minutes
at -f at-file now + 1 hour

Le calendrier Unix

Utilisez la commande 'calendar' pour prévoir des rendez-vous et des évènements. Créez un fichier texte (nom par défaut 'calendar') contenant un mois, une date et un évènement sur chaque ligne.

% cat calendar

10 April Jeudi's job
20 April Sunday's job
26 April Saturday's job

04/01 April Fool
04/20 Sunday's job
04/29 Dentist

Affichez les évènements pour une date donnée (spécifiée comme MMJJ) avec les commandes suivantes :

% calendar -d 0410
10 April Jeudi's job

% calendar -d 0429
04/29 Dentist

Pour aujourd'hui (le 20 avril dans cet exemple), vous pouvez vous passer de préciser la date :

% calendar
20 April Sunday's job
04/20 Sunday's job

Si le fichier n'est pas 'calendar' dans le répertoire actuel, utilisez l'option '-f' :

% calendar -f /path/name/file-name -d 0429
04/29 Dentist

Unix a des fichiers de calendrier déjà prêts dans :

/usr/share/calendar

Par exemple :

% calendar -f /usr/share/calendar/calendar.holiday -d 0421
04/21   San Jacinto Day in Texas
04/22   Arbor Day in Nebraska & Delaware
04/22   Oklahoma Day in Oklahoma
04/21   Tiradentes in Brazil

ping

Nous connaissons tous le vénérable utilitaire 'ping'.

- il peut vérifier si une machine est active
- il peut vérifier si votre connexion réseau est en bon état
- il peut faire un bilan de la réactivité générale de tout ce qui se dirige vers une machine particulière (le champ 'time=')
- il peut trouver l'adresse IP d'une machine

Par exemple :

% ping apple.com
PING apple.com (17.254.3.183): 56 data bytes
64 bytes from 17.254.3.183: icmp_seq=0 ttl=45 time=165.922 ms
64 bytes from 17.254.3.183: icmp_seq=1 ttl=45 time=165.541 ms

L'option '-i' peut être utilisée pour changer l'intervalle entre les envois de ping, et l'option '-c' peut être utilisée pour envoyer un nombre spécifié de pings. Par exemple, pour faire un ping à Apple une fois par minute (définie comme 60 secondes) pendant 30 minutes :

ping -i 60 -c 30 apple.com

(Le nom 'ping' vient du son que font les sonars.)


Astuces pour ping

Essayer de pinger toutes les machines sur votre réseau local pour voir celles qui utilisent Rendezvous :

% ping 224.0.0.251

Pingez l'adresse de broadcast de votre sous réseau local pour découvrir toutes les machines qui s'y trouvent :

% ping 10.0.1.255

ou

% ping 192.168.1.255

Regardez si votre routeur répond à :

% ping 0

et qui répond à :

% ping 255.255.255.255

Vous pouvez pinger une machine AppleTalk avec 'appleping'.


traceroute

L'utilitaire traceroute montre le chemin vers des machines distantes en indiquant chaque 'hop' (saut) que fait un paquet sur son chemin à travers Internet.

La route est longue vers OSXFAQ.com...

% traceroute osxfaq.com
traceroute to osxfaq.com (64.84.37.30), 30 hops max, 40 byte packets
1  valinor.zen (217.155.168.150)  21.229 ms  0.819 ms  0.353 ms
2  gauss-dsl1.wh.zen.net.uk (62.3.83.2)  19.78 ms  19.17 ms  20.999 ms
3  chrysippus-ve-131.wh.zen.net.uk (62.3.83.78)  22.385 ms  21.946 ms  22.521 ms
4  deleuze-ge-0-2-0.hq.zen.net.uk (62.3.80.81)  23.122 ms  22.709 ms  22.613 ms
5  suarez-so-0-0-0.te.zen.net.uk (62.3.80.62)  29.521 ms  29.589 ms  29.233 ms
6  lndnuk1icx1.wcg.net (195.66.224.105)  29.292 ms  29.049 ms  29.994 ms
7  nycmny2wcx2-oc12.wcg.net (64.200.87.149)  100.266 ms  100.063 ms  99.222 ms
8  nycmny2wcx3-oc48.wcg.net (64.200.87.78)  169.294 ms  169.843 ms  169.936 ms
9  chcgil1wcx3-oc48.wcg.net (64.200.240.37)  169.212 ms  170.859 ms  169.893 ms
10  dnvrco1wcx2-pos10-0.wcg.net (64.200.210.66)  169.951 ms  170.472 ms  170.171 ms
11  snfcca1wcx3-pos11-0.wcg.net (64.200.240.94)  170.758 ms  171.265 ms  171.403 ms
12  snfcca1wce1-pos3-0.wcg.net (64.200.199.238)  169.128 ms  170.197 ms  167.675 ms
13  snfcca1wce1-naciosystems-se.wcg.net (64.200.198.18)  168.242 ms  168.977 ms  169.301 ms
14  is10-0-0m.nov55c-75-003.nacio.com (64.84.1.9)  172.06 ms  171.154 ms  169.978 ms
15  if0-0-0m.nov55c-75-002.nacio.com (64.84.0.195)  172.116 ms  172.63 ms  171.409 ms
16  is11-1-1m.sfob-02.nacio.com (167.160.242.253)  173.154 ms  174.414 ms  173.645 ms
17  ife0-0m.sfoc-01.nacio.com (167.160.239.177)  173.634 ms  172.496 ms  173.64 ms
18  gw.scotthaneda.m-l.net (167.160.239.194)  178.804 ms  178.785 ms  177.821 ms
19  osxfaq.com (64.84.37.30)  179.822 ms  181.029 ms  182.053 ms

Si traceroute rate, essayer l'option '-p' avec un nombre de port élevé :

% traceroute -v -p 35353 osxfaq.com

version graphique de traceroute

Essayez ce très bon site web pour une version plus graphique de traceroute :

http://visualroute.visualware.co.uk/

netstat

netstat fournit un certain nombre de statistiques vitales sur vos connexions réseau, vos tables de routage et d'autres informations du même type. Il est utile pour debugger votre connexion, ou juste pour fouiner un peu.

Quelques exemples :

Pour avoir une liste des connexions actuelles, incluant les noms des machines et les numéros de port locaux :

% netstat
Active Internet connections
Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)
tcp4       0    286  saruman.zen.55040      osxfaq.com.http        ESTABLISHED
tcp4       0    284  saruman.zen.55039      osxfaq.com.http        ESTABLISHED
tcp4       0      0  saruman.zen.55038      osxfaq.com.http        CLOSE_WAIT
tcp4       0      0  localhost.1033         localhost.1006         ESTABLISHED
tcp4       0      0  localhost.1006         localhost.1033         ESTABLISHED
tcp4       0      0  localhost.1033         localhost.1019         ESTABLISHED
tcp4       0      0  localhost.1019         localhost.1033         ESTABLISHED
tcp4       0      0  localhost.1033         *.*                    LISTEN
udp4       0      0  saruman.zen.ntp        *.*                    
udp4       0      0  localhost.ntp          *.*                    
udp4       0      0  localhost.49155        localhost.1002         
udp4       0      0  localhost.49154        localhost.1002         
udp4       0      0  localhost.1033         *.*                    
Active LOCAL (UNIX) domain sockets
Address  Type   Recv-Q Send-Q    Inode     Conn     Refs  Nextref Addr
25b2540 stream   4782      0        0        0        0        0
25b23b8 stream      0      0        0  25b24d0        0..
......
......
......

Pour avoir une liste des tables de routage de votre machine :

% netstat -r
Routing tables

Internet: Destination Gateway Flags Refs Use Netif Expire default valinor.zen UGSc 36 433 en0 localhost localhost UH 8 26887 lo0 169.254 link#4 UCS 0 0 en0 217.155.168.144/29 link#4 UCS 1 0 en0 saruman.zen localhost UHS 0 96 lo0 valinor.zen 0:50:7f:6:82:34 UHLW 36 201 en0 1072
Internet6: Destination Gateway Flags Netif Expire UH lo0 fe80::%lo0 Uc lo0 link#1 UHL lo0 fe80::%en0 link#4 UC en0 0:3:93:b2:d6:4 UHL lo0 fe80::%en1 link#5 UC en1 0:30:65:6:59:b2 UHL lo0 ff01:: U lo0 ff02::%lo0 UC lo0 ff02::%en0 link#4 UC en0 ff02::%en1 link#5 UC en1

(Utilisez l'option '-n' pour afficher les adresses IP au lieu des noms de machines.)

Vous devriez voir le routeur par défaut, votre nom de routage/adresse IP et son adresse MAC, en plus de plusieurs noms et adresses assignés à votre machine.

La commande :

arp -a

vous montre toutes les machines sur le sous réseau local pour lesquelles votre machine a un lien MAC à adresse IP. Quand vous êtes connectés à un routeur, vous ne verez probablement que les détails de votre routeur.


Demander des informations sur une machine avec 'host'

Pour obtenir l'adresse IP d'une machine, utilisez :

% host mayo-family.com.
mayo-family.com has address 64.84.37.15
mayo-family.com mail is handled (pri=10) by mail.hostwizard.com

Cette commande retourne aussi le serveur mail pour ce domaine.

Il est conseillé de finir le nom de domaine avec un '.' (comme dans l'exemple ci-dessus) pour s'assurer qu'il ne soit pas interprété comme appartenant à votre propre domaine.

Pour faire l'inverse, c'est-à-dire obtenir un nom de machine à partir d'une adresse IP, donnez simplement l'adresse IP :

host 17.254.3.183
183.3.254.17.IN-ADDR.ARPA domain name pointer apple.com

(Voir aussi la Semaine 42 pour plus de conseils Internet.)


Des astuces pour 'host'

'host' a un certain nombre d'options. La plus utile est '-a' pour récupérer tous les enregistrements et afficher en mode explicite.

  % host -a mayo-family.com
  Trying null domain
  rcode = 0 (Success), ancount=5
  The following answer is not authoritative:
  The following answer is not verified as authentic by the server:
  mayo-family.com 79546 IN        MX      10 mail.hostwizard.com
  mayo-family.com 79546 IN        A       64.84.37.15
  mayo-family.com 79546 IN        NS      ns1.hostwizard.com
  mayo-family.com 79546 IN        NS      dns2.intermag.com
  mayo-family.com 79546 IN        NS      dns3.intermag.com
  For authoritative answers, see:
  mayo-family.com 79546 IN        NS      dns2.intermag.com
  mayo-family.com 79546 IN        NS      dns3.intermag.com
  mayo-family.com 79546 IN        NS      ns1.hostwizard.com
  Additional information:
  mail.hostwizard.com     65327 IN        A       64.84.37.6
  ns1.hostwizard.com      80083 IN        A       64.84.37.14
  dns2.intermag.com       882 IN  A       216.218.240.104
  dns3.intermag.com       883 IN  A       198.144.200.118

Notez que :

  • A = adresse IP
  • MX = serveur mail
  • NS = serveur de nom

'dig' et 'nslookup'

Les commandes 'dig' et 'nslookup' sont des alternatives à 'host' et peuvent être mieux adaptées à vos besoins.

% dig apple.com.

; <> DiG 8.3 <> apple.com. ;; res options: init recurs defnam dnsrch ;; got answer: ;; ->HEADER<- opcode: QUERY, status: NOERROR, id: 2 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 6, ADDITIONAL: 4 ;; QUERY SECTION: ;; apple.com, type = A, class = IN
;; ANSWER SECTION: apple.com. 26m56s IN A 17.254.3.183
;; AUTHORITY SECTION: apple.com. 1d23h43m9s IN NS nserver.asia.apple.com. apple.com. 1d23h43m9s IN NS nserver.euro.apple.com. apple.com. 1d23h43m9s IN NS nserver.apple.com. apple.com. 1d23h43m9s IN NS nserver2.apple.com. apple.com. 1d23h43m9s IN NS nserver3.apple.com. apple.com. 1d23h43m9s IN NS nserver4.apple.com.
;; ADDITIONAL SECTION: nserver.asia.apple.com. 1d8h48m29s IN A 203.120.14.5 nserver.euro.apple.com. 23h13m18s IN A 17.72.133.64 nserver3.apple.com. 4d22h14m31s IN A 17.112.144.50 nserver4.apple.com. 4d22h14m31s IN A 17.112.144.59
;; Total query time: 47 msec ;; FROM: saruman.mayo-family.com to SERVER: default -- 212.23.8.1 ;; WHEN: Sun May 4 20:47:50 2003 ;; MSG SIZE sent: 27 rcvd: 252

% nslookup apple.com. Server: ns0.zen.co.uk Address: 212.23.8.1
Non-authoritative answer: Name: apple.com Address: 17.254.3.183

Comme toujours, utilisez la commande 'man' pour en savoir plus.


'whois'

La commande 'whois' fait une requête à whois.intemic.net pour découvrir le responsable, le propriétaire et les serveurs de nom pour un domaine.

% whois mayo-family.com

Whois Server Version 1.3
...
Domain Name: MAYO-FAMILY.COM Registrar: BULKREGISTER.COM, INC. Whois Server: whois.bulkregister.com Referral URL: http://www.bulkregister.com Name Server: DNS2.INTERMAG.COM Name Server: NS1.HOSTWIZARD.COM Name Server: DNS3.INTERMAG.COM Status: ACTIVE Updated Date: 27-feb-2003 Creation Date: 19-jul-2001 Expiration Date: 19-jul-2003 ...
Si le domaine n'a pas été enregistré par intemic, un deuxième whois est nécessaire. Dans ce cas une requête au serveur whois du responsable est nécessaire avec l'option '-h'.
% whois -h whois.bulkregister.com mayo-family.com Adrian Mayo 54 Greenland Mills Bradford-on-Avon, England BA15 1BL UK
Domain Name: MAYO-FAMILY.COM
Administrative Contact: Carlton Thomas domreg@gifford.co.uk Gifford Internet Services 14 Tyrrel Way, Stoke Gifford Bristol, England BS34 8UY UK Phone: +44 117 9397722 Fax: +44 117 9397733 Technical Contact: Carlton Thomas domreg@gifford.co.uk Gifford Internet Services 14 Tyrrel Way, Stoke Gifford Bristol, England BS34 8UY UK Phone: +44 117 9397722 Fax: +44 117 9397733
Record updated on 2001-07-19 11:28:07 Record created on 2001-07-19 Record expires on 2003-07-19 Database last updated on 2003-05-04 15:58:47 EST
Domain servers in listed order:
DNS2.INTERMAG.COM 216.218.240.104 DNS3.INTERMAG.COM 198.144.200.118 NS1.HOSTWIZARD.COM 64.84.37.14

'whois' pour les domaines non TLD

Pour faire une requête 'whois' pour un domaine qui n'est pas du plus haut niveau (Top Level Domain en anglais), par exemple '.co.uk', il faut utiliser un autre service 'whois'.

% whois -h whois.nic.uk bbc.co.uk

Domain Name: bbc.co.uk
Registrant: British Broadcasting Corporation
Registrant's Agent: The British Broadcasting Corporation t/a BBC Technology [Tag = BBC]
Relevant Dates: Last updated: 13-Mar-2001
Name servers listed in order: ns.bbc.co.uk 132.185.132.21 ns1.thny.bbc.co.uk 38.160.150.21 ns1.thdo.bbc.co.uk 212.58.224.21 ns1.bbc.co.uk 132.185.132.11
WHOIS database last updated at 21:20:01 04-May-2003

Et si quelqu'un connait une façon fiable de déterminer l'adresse whois pour les divers TLD et domaines nationaux, faites le nous savoir...


Shells secondaires

Pour exécuter une commande, ou des commandes, dans un nouveau shell, utilisez des parenthèses.

Pour exécuter plusieurs commandes sur une ligne, séparez les avec des point-virgules.

Par exemple, comparez les deux commandes suivantes qui font appel aux deux méthodes.

% (cd /; pwd); pwd 
/
/Users/saruman 

% cd / ; pwd ; pwd / /

Pour savoir pourquoi les sorties diffèrent, reportez vous à la partie 8 du manuel Unix dans le Learning Center (en anglais sur osxfaq.com).

Mac OS X Unix Tutorial 8 - Shell Scripting 1. New 19 May 2003


Redirection

Ceci s'applique au shell 'tcsh'.

Pour rediriger une sortie standard, utilisez '>'. Ex :

ls -al * > list

Les sorties et les messages d'erreur écrivent dans différents flux. Pour rediriger à la fois les sorties standards et les erreurs standards, utilisez '>&'. Ex :

ls -al kfhsdhdjhsjkhf >& list

Pour en savoir plus sur la redirection, reportez vous à la partie 7 du manuel Unix dans le Learning Centre (en anglais sur osxfaq.com).

Mac OS X Unix Tutorial 8 - Shell Scripting 1. New 19 May 2003


Redirection 2

Le shell 'tcsh' ne permet pas de façon évidente de rediriger une sortie standard et une erreur vers des fichiers différents. Utilisez l'astuce suivante pour y arriver :

(ls -al filename > list ) >& list.err

Pour en savoir plus sur la redirection, reportez vous à la partie 7 du manuel Unix dans le Learning Centre (en anglais sur osxfaq.com).

Mac OS X Unix Tutorial 8 - Shell Scripting 1. New 19 May 2003


Redirection 3

Le shell 'tcsh' ne permet pas de façon évidente de rediriger une erreur standard, mais pas la sortie standard. Utilisez l'astuce suivante pour y arriver :

(ls -al filename > /dev/tty) >& list.err

Mac OS X Unix Tutorial 8 - Shell Scripting 1. New 19 May 2003


Comment éviter les écrasements intempestifs de fichier

Si vous voulez éviter d'écraser accidentellement des fichiers avec des redirections, activez la variable 'noclobber' de 'tcsh'. Par exemple :

% set noclobber
% ls 
.....list list.err ....

% ls > list list: File exists. % ls >! list %

Remarquez l'utilisation de '!' pour temporairement passer outre 'noclobber'.

Mac OS X Unix Tutorial 8 - Shell Scripting 1. New 19 May 2003


Comment tuer un job

Pour tuer une application (ou un process) de la ligne de commande, nous devons d'abord trouver le numéro qui lui a été alloué : son Process ID ou PID. Par exemple :

% ps -axww | grep -i clock
15048  ??  S      0:00.65 /Applications/Clock.app/Contents/MacOS/Clock
15054 std  R+     0:00.00 grep -i clock

et ensuite utiliser la commande 'kill' :

% kill 15048

Remarquez l'utilisation de l'option 'ww' qui assure que la sortie de 'ps' n'est pas tronquée, elle perdrait alors le nom pour lequel nous utilisons grep.

Un PID de -1 propage le signal à tous les process pour lesquels vous avez la permission nécessaire pour tuer.

Une autre façon de procéder est d'utiliser :

killall Clock

qui tue par nom (sensible à la casse). Faites attention car cette commande tue tous les process qui correspondent au nom donné.

L'option '-m' de 'killall' prend une expression régulière en tant que nom de process, et tue tous les process qui lui correspondent.


Beaucoup de façons de tuer

Les commandes 'kill' et 'killall' envoient un signal 'TERM' au process, ce signal correspond à une demande au process de s'arrêter.

D'autres signaux sont disponibles, incluant

-KILL - fait au process une proposition qu'il ne peut refuser. Ceci tue toujours le process.

-HUP - dit au process de redémarrer. C'est utile pour redémarrer des démons (comme configd et lookupd), car ils vont relire leur fichier de configuration à la réception d'un signal -hup.

La commande :

% kill -l

liste tous les signaux disponibles, et :

% man sigaction

donne plus de détail.


Le Script Assassin

Voici un script pratique pour tuer des processus par leur nom :

% cat killer
#!/bin/sh
kill $(ps auxww | grep -i $1 | grep -v $1 | awk '{print $2}')

% killer clock
*gone!*

N'oubliez pas de rendre le script exécutable.


Trouver votre victime

Plusieurs démons Unix laisse gentiment leur adresse. Voyez plutôt :

% ls /var/run/
AppleFileServer.pid  cron.pid     mDNSResponder.pid   ntp.drift    sshd.pid    xinetd.pid
StartupItems         davlocks     named.pid           ntpd.pid     sudo
autodiskmount.pid    httpd.pid    ndc                 pppconfd     syslog
automount.pid        inetd.pid    netinfo_local.pid   proxy        syslog.pid
configd.pid          lookupd.pid  niconfig_local.xml  resolv.conf  utmp

Elles devraient être indépendantes du nom du démon. Par exemple, les serveurs www devraient afficher leur pid dans 'httpd.pid'.

Vous pouvez créer un alias pratique pour redémarrer un démon :

% alias nfs-mount 'sudo kill -HUP `cat /var/run/automount.pid`'
% alias nfs-export 'sudo kill -HUP `cat /var/run/mountd.pid`'

ce qui redémarrera le client et le serveur NFS après que de nouveaux partages et de nouvelles connexions aient été ajoutés.


Le Script de Pendaison

Voici un script pratique pour redémarrer un démon :

% cat hanger
#!/bin/sh
if [ "$1" = "" ]; then
  echo "Liste des démons :"
  cd /var/run
  ls -1 *.pid | sed -e 's/.pid//'
else
  echo "redémarrage du démon $1"
  sudo kill -HUP `cat /var/run/$1.pid`
fi

Il listera les démons :

~ % hanger
List of demons:
AppleFileServer
autodiskmount
automount
configd
cron
httpd
inetd
lookupd
mDNSResponder
named
netinfo_local
ntpd
sshd
syslog
xinetd

et les tuera :

% hanger lookupd
redémarrage du démon lookupd

N'oubliez pas de rendre le script exécutable.


Démarrer et Arrêter Apache

Pour démarrer et arrêter Apache à partir de la ligne de commande, utilisez l'utilitaire de contrôle d'Apache :

% sudo apachectl start
/usr/sbin/apachectl start: httpd started

% sudo apachectl stop
/usr/sbin/apachectl stop: httpd stopped

Pour faire en sorte qu'Apache démarre lorsque vous démarrez votre Mac, éditez le fichier :

/etc/hostconfig

en étant sous root, et changez

WEBSERVER=-NO-

en

WEBSERVER=-YES-

Redémarrer Apache

Si vous changez les fichiers de configuration d'Apache, vous devez redémarrer Apache pour qu'il les lise de nouveau. Pour faire ceci avec grace (sans perturber les connexions existantes d'un serveur en ligne), utilisez :

% sudo apachectl graceful
/usr/sbin/apachectl graceful: httpd gracefully restarted

Changer le répertoire root du WebServer

Par défaut, Apache sur Mac OS X utilise comme point de départ /Library/WebServer/Documents. Si vous voulez utiliser un autre répertoire, comme ~/Sites, éditez le fichier de configuration d'Apache :

% sudo pico /etc/httpd/httpd.conf

Remplacez cette ligne (ligne 363?) :

DocumentRoot "/Library/WebServer/Documents"

par :

DocumentRoot "/Users/your-user-name-here/Sites"

et cette ligne (ligne 388?) :

Directory "/Library/WebServer/Documents"

par :

Directory "/Users/your-user-name-here/Sites"

Le manuel Apache

Vous pouvez accéder au manuel Apache en ligne avec l'URL : http://localhost/manual/


Les fichiers d'accès Apache

Apache écrit les informations d'accès dans :

/private/var/log/httpd/error_log

et :

/private/var/log/httpd/access_log

Examinez le registre d'erreur si vous avez des soucis en mettant en place le serveur. Examinez le registre d'accès pour voir qui regarde votre site.

Vous pouvez changer la quantité d'information de connexion qui est écrite dans ces fichiers. Par exemple, pour ajouter au fichier d'accès le site qui s'est connecté au vôtre et l'agent de l'utilisateur (le navigateur), procédez de la façon suivante.

Editez le fichier de configuration Apache

% sudo pico /etc/httpd/httpd.conf

Cherchez :

CustomLog "/private/var/log/httpd/access_log" common

Et remplacez le par :

CustomLog "/private/var/log/httpd/access_log" combined

Obtenir la liste des commandes intégrées au Shell

Le shell tcsh possède beaucoup de commandes intégrées pratiques (des commandes qui font partie du shell mais n'existent pas comme exécutables séparés dans /bin etc).

Pour faire la liste de toutes les commandes intégrées :

% builtins
:       @         alias      alloc   bg   bindkey
break   breaksw   builtins   case    cd   chdir
...

Si la même commande existe à la fois comme exécutable séparé et comme commande intégrée du shell, c'est la commande intégrée qui sera exécutée. Pour utiliser l'exécutable, commencez la commande par "\".

% which which
which: shell built-in command.

% which \which
/usr/bin/which

et essayez ceci :
% \which which

La table de hachage des commandes

Quand on donne au shell une commande à exécuter, il cherche d'abord dans ses commandes intégrées, et ensuite dans tous les répertoires spécifiés dans les variables PATH ou path environment/shell. Pour voir le chemin d'accès, utilisez une de ces deux commandes :

% echo $PATH
% echo $path

De façon à accélérer ce processus de recherche, le shell cherche dans ces répertoires quand il démarre et il stocke l'information en mémoire. Si vous ajoutez une nouvelle commande ou un script shell à un de ces répertoires, le shell ne les reconnaitra pas. Pour que le shell rafraîchisse son cache, utilisez la commande intégrée 'rehash'

% rehash

S'il n'y a pas de réponse, c'est que tout va bien.

Essayez ceci :

% hashstat

umask

La commande intégrée 'umask' indique au système de fichier les permissions par défaut qu'il doit appliquer aux fichiers et aux répertoires qui vont être créés. umask peut être placée dans votre fichier de démarrage tcsh, ou juste appliquée à une session de Terminal particulière.

Sans umask, les répertoires ont les permissions suivantes :

drwxrwxrwx 2 saruman staff 68 Jun 9 11:16 test-dir

et les fichiers ont les permissions suivantes :

-rw-rw-rw- 1 saruman staff 0 Jun 9 11:16 test-file

En général, umask est réglée sur 022 :

% umask 022
% touch test-file
% ls -al test-file
-rw-r--r--   1 saruman  staff           0 Jun  9 11:22 test-file

Pour donner la permission d'écriture à votre groupe :

% rm test-file
% umask 002
% touch test-file
% ls -al test-file
-rw-rw-r--   1 saruman  staff           0 Jun  9 11:23 test-file

Pour les fichiers partagés :

% rm test-file
% umask 000
% touch test-file
% ls -al test-file
-rw-rw-rw-   1 saruman  staff           0 Jun  9 11:23 test-file

Pour les fichiers privés :

% rm test-file
% umask 077
% touch test-file
% ls -al test-file
-rw-------   1 saruman  staff           0 Jun  9 11:23 test-file

La commande intégrée 'nice'

La commande intégrée 'nice' est utilisée pour exécuter une commande avec une priorité plus élevée ou moins élevée que la priorité par défaut. Une valeur négative de nice assure que la commande bénéficie d'une plus grande part du CPU (haute priorité), et une valeur positive assure que la commande en obtient une part plus petite (basse priorité).

Normalement, une commande est créée avec une valeur de nice de 4 :

% ./test.sh

% ps -axlhww | grep test.sh UID PID PPID CPU PRI NI ... 501 9997 3457 0 27 4 ...

indiquant une priorité (PRI) de 31-4=27 et in nice (NI) de 4.

Pour créer une commande de basse priorité, utilisez :

% nice +20 ./test.sh
% ps -axlhww | grep test.sh
  UID   PID  PPID CPU PRI NI ...
  501 10036  3457   0  11 20 ...

indiquant une priorité de 31-20=11 (basse) et un nice de 20 comme on l'a demandé.

Pour augmenter la priorité, il faut être super-utilisateur :

% sudo -s
# nice -10 ./test.sh 
% ps -axlhww | grep test.sh
  UID   PID  PPID CPU PRI NI ...
    0 10142 10130   0  41 -10 ...

Vous pouvez aussi regarder la commande 'renice' (non intégrée), qui ajuste la priorité des processus en cours :

% man renice

exec

La commande intégrée 'exec' permet à un utilisateur d'exécuter une commande à la place du shell. Le shell lance la commande et se retire.

Cela peut être utile pour lancer une commande qui s'exécute comme un démon et ne nécessite pas son shell d'origine.

% exec my-daemon

Démarrage du Shell

Quand le shell 'tcsh' démarre, il lit et exécute plusieurs fichiers de script. Vous êtes libres de les changer (ou d'en créer) si vous voulez personnaliser votre environnement en ligne de commande. Ces fichiers sont :

/etc/csh.cshrc
/etc/csh.login

~/.tcshrc
~/.login

Vous pouvez ajouter des commandes Unix ou des commandes du shell 'tcsh' à ces fichiers. Les deux premiers fichiers concernent tous les utilisateurs, et les deux suivants sont propres à chaque utilisateur.


tcshrc et cshrc

Pour une compatibilité en amont avec le shell 'csh' (à partir duquel est dérivé le shell 'tcsh'), le fichier de script :

~/.cshrc

peut ou ne peut pas être exécuté quand le shell 'tcsh' démarre.

En l'absence de '~/.tcshrc', '~/.cshrc' est exécuté. A partir du moment où vous créez '~/.tcshrc', '~/.cshrc' n'est plus exécuté. Ainsi, ne vous contentez jamais d'avoir ces deux fichiers exécutés. Choisissez en un, de préférence '~/.tcshrc', et utilisez le même si on vous conseille de rajouter des lignes à l'autre. Les deux sont interchangeables.


Shells de Connexion et d'Interaction

A quoi correspondent les Shell de Connexion et d'Interaction ?

L'ouverture d'une fenêtre Terminal lance un shell interactif avec connexion.

L'exécution d'un script shell lance un shell non interactif sans connexion.

Taper 'tcsh' à la ligne de commande lance un shell interactif sans connexion.

Les shells avec connexion diffèrent de part le fait qu'ils lisent et exécutent :

/etc/csh.login
~/.login

alors que les shells sans connexion ne le font pas.

Les shells interactifs sont attachés à une fenêtre de Terminal de façon à ce que vous puissiez y taper des commandes. Les shells non interactifs obtiennent leurs commandes à partir d'un script.

Quelques terminaux (tels que xterm qui tourne sous X11) ne lance pas par défaut de shell de connexion. Pour faire en sorte que xterm le fasse, et donc se comporter comme le Terminal dApple, ajoutez ceci à ~/.Xdefaults :

# xterm
XTerm*.LoginShell: True

Commandes de Connexion exclusivement

Suite de l'astuce de Mercredi ...

Optimisez la séquence de démarrage du shell en utilisant les fichiers de démarrage du shell exclusivement de connexion :

/etc/csh.login
~/.login

Dans ces fichiers, configurez l'aspect de l'environnement qui persiste, tel que les variables d'environnement. Cela s'applique surtout aux commandes du genre :

setenv PATH ${PATH}:xxx

qui en rajoute à une variable d'environnement. Une commande comme celle-ci ne doit pas être exécutée plus d'une fois sinon votre PATH va grandir et grandir encore.


Commandes exclusivement Interactives

Suite de l'astuce de Mercredi ...

Optimisez le séquence de démarrage du shell. Beaucoup de commandes dans in ~/.tcshrc ne sont pas nécessaires pour les shells non interactifs. La plupart, en fait, comme celles qui configurent les variables shell et les alias, et la commande bindkey. Sortez ces commandes pour les shells non interactifs.

Incorporez cette instruction près du début de ~/.tcshrc

if ($?prompt) set interactive

Puis entourez toutes les commandes exclusivement interactives avec :

if ($?interactive) then

... lieu des commandes interactives...

endif

'xargs'

Des astuces précédentes (des semaines 1, 13 et 31—pas encore traduites sur Project:Omega) ont abordé le 'find'. Les astuces de cette semaine vont plus loin d'utilisation cette commande puissante en combinaison avec la commande 'xargs'.

La Semaine 13 (en anglais) donnait un exemple d'utilisation de l'option '-exec' du 'find' pour exécuter une commande sur tous les fichiers trouvés :

% find . -iname "*.ws" -exec grep -il warning {} ;
./week13/thursday.ws
./week21/thursday.ws
./week5/friday.ws
./week5/thursday.ws
./week9/monday.ws

Le même effet peut être obtenu en montant un 'pipe' avec 'xargs' :

% find . -iname "*.ws" | xargs grep -il warning
./week13/thursday.ws
./week21/thursday.ws
./week5/friday.ws
./week5/thursday.ws
./week9/monday.ws

'xargs' est une commande Unix de plein droit et n'est pas spécifique à 'find'. Elle constitue une commande à partir des paramètres qui proviendront de la sortie de la commande 'find'.

grep -il warning file1 file2 file3 file4 .......

'xargs' vs '-exec'

Cette astuce se réfère à celle de lundi...

% find . -iname "*.ws" -exec grep -il warning {} ;

contre :

% find . -iname "*.ws" | xargs grep -il warning

...certains pourront vous dire que monter un 'pipe' avec 'xargs' est moins efficace que d'utiliser l'option intégrée '-exec'. Ce n'est pas le cas, et en fait, le deuxième exemple ira au moins dix fois plus vite que le premier...

Pourquoi?

Parce que '-exec' exécutera la commande 'grep' une fois pour chaque fichier trouvé. Dans cet exemple, plus de 200 fichiers correspondaient à "*.ws". 'xargs' d'un autre côté, absorbe tous les arguments et les passe à 'grep' en une fois.


Les options de 'xargs'

L'exemple de lundi...

% find . -iname "*.ws" | xargs grep -il warning

...marche car 'grep' peut prendre une longue liste de fichiers à traiter. Si une commande ne prend qu'un fichier à la fois, utilisez l'option '-n1'.

% find . -iname "*.ws" | xargs -n1 my-simple-script

L'option '-t' est utile (trace) - elle fait en sorte que 'xargs' mette en sortie standard la commande qu'il a formée et qu'il va exécuter.

% find . -iname "*.ws" | xargs grep -t -il warning
grep -il warning ./index.ws ./week1/friday.ws ./week1/monday.ws
./week1/thursday.ws ./week1/tuesday.ws ./week1/wednesday.ws
./week10/friday.ws ./week10/monday.ws ./week10/thursday.ws
...
./week8/friday.ws ./week8/monday.ws ./week8/thursday.ws
./week8/tuesday.ws ./week8/wednesday.ws ./week9/friday.ws
./week9/monday.ws ./week9/thursday.ws ./week9/tuesday.ws

./week9/wednesday.ws
./week13/thursday.ws
./week21/thursday.ws
./week5/friday.ws
./week5/thursday.ws
./week9/monday.ws

Trop de fichiers?

Si 'find' trouve beaucoup, beaucoup de fichiers, la ligne de commande résultante formée par 'xargs' peut être trop longue. Limitez-la en utilisant l'option '-n' qui indique le nombre maximum de paramètres que 'xargs' passera à la commande (à 'grep' dans cet exemple).

% find . -iname "*.ws" | xargs -n100 grep -il warning

...fait en sorte que 'xargs' appelle 'grep' une fois qu'il a 100 noms de fichier. Si 350 noms de fichier étaient trouvés, 'xargs' appellerait 'grep' quatre fois.


Prenez Vim

Prenez vim. Mac OS X embarque 'vi'. Vim est une version améliorée de 'vi', et il est disponible en trois versions : Terminal pur, X11 et GUI Carbon.

La page d'accueil principale de vim est : http://www.vim.org

La page de téléchargement de la version Mac est : http://www.vim.org/download.php#mac

Pour la version Interface Graphique Carbon : http://macvim.swdev.org/OSX

Marc Liyanage maintient les versions ligne de commande des déclinaisons Terminal pur et X11 : http://www.entropy.ch/software/macosx/welcome.html#vim

Les astuces de cette semaine ne sont pas un tutoriel sur vim pour les débutants mais elles seront pratiques pour ceux qui ont dépassé le stade de la touche 'esc' et de la touche 'i'.


Mouvement du Curseur

Apprenez les touches de mouvement du curseur. Les plus utiles sont :

{ retour au début du paragraphe
( retour au début de la phrase
- retour au début de la ligne précédente
^ retour au début de la ligne
b retour au début du mot
w avance au début du mot
$ avance vers la fin de la ligne
+ avance au début de la ligne suivante
) avance au début de la prochaine phrase
} avance au début du prochain paragraphe
G vers la fin du fichier

(plus les touches curseur évidentes).


Couper, copier et coller

Utiliser couper, copier et coller :

d coupe (delete)
y copie (yank)
p colle (paste—au-dessous de la ligne courante, et P colle au-dessus)

y et d doivent être suivies par un mouvement de curseur (voir l'astuce de Mardi) et elles copieront ou effaceront à partir du curseur jusqu'à l'emplacement de déplacement cible.

Exemples :

d$ efface jusqu'à la fin de la ligne
d) efface jusqu'à la fin de la phrase
(y) copie la phrase entière, quel que soit l'endroit du curseur dans la phrase

Raccourcis :

dd est le raccourci pour effacer la ligne courante
yy est le raccourci pour copier la ligne courante

Utilisez les 26 buffers

Vim comporte 26 buffers (de a à z) en plus du buffer général sans nom. Précédez une commande d'un nom de buffer et la commande chagera ce buffer ou en retirera ses informations.

Suite de l'exemple de Mercredi :

"ay) copie jusqu'à la fin de la phrase et place le texte dans le buffer nommé "a
"ap colle le texte qui se trouve dans le buffer "a

Notez que le buffer sans nom est toujours mis à contribution en plus de n'importe quel buffer nommé.

Vous pouvez ajouter du texte à un buffer en le nommant avec une lettre majuscule.

"Ad$ coupera le texte jusqu'à la fin de la ligne et ajoutera le texte coupé à celui déjà présent dans le buffer "a

Signets

Vim est doté de 26 signets intitulés de a à z. Placez un signet avec ma (jusqu'à mz) et rappelez le (replacez le cursuer à cet endroit) avec 'a (jusqu'à 'z).

Copiez ou collez une portion de texte avec :


ma

"by'a

Cela copiera en plus la section dans le buffer intitulé "b.

En plus :

'' (deux guillemets) alterne entre la position courante et la position précédente du curseur
'a déplace vers le début de la ligne marquée
`a déplace vers la position du caractère marqué dans la ligne marquée

Constituez des signets sur plusieurs fichiers avec les 36 signets inter-fichier mA (jusqu'à mZ, et m0 à m9). Rappelez les comme d'habitude avec 'A ou `A (jusqu'à 'Z, '9).


...pour Additionner des Tailles de Fichiers

Les astuces de cette semaine sont tirées des réponses envoyées aux nombreux mails que j'ai reçus me demdant : "Comment faire ceci et cela ?"

Comment puis je faire pour avoir le total de tous les fichiers Photoshop (*.psd) situés dans mon répertoire Départ ?

% find ~ -iname "*.psd" -print0 | xargs -0 du -ch
15M ./Pictures/complete/ferdi-coll3.psd
30M ./Pictures/complete/ferdi-cool.psd
1.7M ./Pictures/complete/ferdi-gala.psd
...
600k ./Pictures/web-site/misc/web5.psd
72k ./Pictures/web-site/osxfaq/banner1.psd
48k ./Pictures/web-site/osxfaq/banner2.psd
96k ./Pictures/web-site/osxfaq/btn-.psd
28k ./Pictures/web-site/osxfaq/end.psd
316M total

Voilà ! - 316M.

La commande standard Mac OS X 'du' ne comprend pas l'option '-h' (affichage lisible par un humain). Utilisez -k à la place pour voir les tailles de fichiers en K-octets.

Le package GNU 'fileutils' contient des versions plus récentes de beaucoup de commandes de base, dont 'du' et une version colorisée de 'ls'. Il s'obtient plus facilement en utilisant Fink.


...des Recherches dans d'Importants Répertoires

Comment faire pour afficher les Répertoires dont le contenu dépasse les 100 Mo ?

Des astuces précédentes ont couvert une question similaire applicable à tous les fichiers qui dépassent une taille donnée. Par exemple, trouver tous les fichiers dont la taille dépasse 20 Mo :

% find . -size +40000

Pour appliquer ceci à des répertoires, utilisez :

% du -k ~ | egrep "^[0-9]{6,}"
139252 /Users/saruman/Library
267020 /Users/saruman/Pictures/complete
357432 /Users/saruman/Pictures/iPhoto Library/2001
214084 /Users/saruman/Pictures/iPhoto Library/2002
195788 /Users/saruman/Pictures/iPhoto Library/2003/01
124948 /Users/saruman/Pictures/iPhoto Library/2003/05
149976 /Users/saruman/Pictures/iPhoto Library/2003/06
545460 /Users/saruman/Pictures/iPhoto Library/2003
1149224 /Users/saruman/Pictures/iPhoto Library
1548924 /Users/saruman/Pictures
1902804 /Users/saruman

Cela affichera le nom des répertoires dont la taille en K-octets est sur six chiffres ou plus (contrôlé par {6,}).


...pour Effacer des Lignes Blanches

Comment faire pour supprimer des lignes vides dans un fichier ?

En utilisant 'sed' :

% sed '/^$/d' in-file > out-file

En utilisant 'tr' :

% tr -s \n < in-file > out-file

Si le fichier comporte des lignes contenant des espaces :

% sed '/^[ ]*$/d' in-file > out-file

Si les lignes contiennent aussi des tabulations :

% sed '/^[ t]*$/d' in-file > out-file

MAIS, la commande 'sed' d'OS X semble ne pas comprendre que 't' veut dire tabulation.


...Traiter une Commande comme une Fonction

Ceci est en rapport avec une question fréquente, mieux illustrée par un exemple.

La commande 'tr' traduit ou retire les caractères du contenu d'un fichier. Comme la plupart des commandes, elle lit et écrit des fichiers ou la sortie standard. Par exemple, pour retirer des espaces utilisez :

% tr -d " " < in-file > out-file

Comment pouvons nous utiliser une commande comme 'tr' dans un script shell pour retirer les espaces dans le contenu d'une variable ? L'effet souhaité est tel que si nous disions :

var = tr ($var);

Le secret tient dans le fait de diffuser le contenu du paramètre d'entrée et de capturer le flux de sortie, ainsi :

Dans tcsh utilisez :

set var=`echo $var | tr -d " "`

Dans sh utilisez :

var=$( echo $var | tr -d " " )

...Retirer les espaces du nom d'un fichier ?

Comment puis-je éliminer les espaces de tous mes noms de fichier ?

Ce script 'sh' fera en sorte de ne pas avoir deux noms de fichier qui diffèrent dans un répertoire que par des espaces et de n'avoir aucun nom de répertoire avec des espaces.

% cat sh2
#!/bin/sh
target_fn=$( echo $1 | tr -d " " )
if [ ! "$1" = "$target_fn" ]; then
  echo mv "$1"  "$target_fn"
  mv "$1"  "$target_fn"
fi

% ls -R1 .: dirname file name file2 name sh sh2 tsh
dirname: file2 name file3name
% find . -print0 | xargs -0 -n1 ./sh2 mv ./dirname/file2 name ./dirname/file2name mv ./file name ./filename mv ./file2 name ./file2name
% ls -R1 .: dirname file2name filename sh sh2 tsh
dirname: file2name file3name

...Utiliser Grep sur plusieurs chaînes (OU)

Comment utiliser grep pour rechercher les fichiers contenant les chaînes string1 OU string2?

% grep -e "apple" -e "microsoft" *.txt

'-e' introduit à une expression régulière de 'grep', qui recherche l'occurence de chacune des expressions régulières listées, dans chaque fichier.

En utilisant le 'grep' étendu ('egrep' ou 'grep -E') on peut spécifier :

% egrep "(microsoft|apple)" *.txt

Le 'grep' étendu comprend les expressions régulières étendues. Le 'grep' dtandard ne comprend que les expression régulières classiques.


...Utiliser Grep sur plusieurs chaînes (ET)

Comment puis-je utiliser 'grep' pour rechercher les chaînes string1 ET string2 dans plusieurs fichiers ?

% grep -l "apple" *.txt | xargs grep -H "microsoft"

'-l' (lettre elle) dans le premier 'grep' fait en sorte qu'il liste que les noms de fichiers, qui sont alors passés au second 'grep'. '-H' indique au second 'grep' d'imprimer le nom de fichier pour chaque correspondance.

Perl et 'awk' feront cela aussi, et j'ai l'intention de les aborder dans un tutoriel du Learning Centre.

Y a t'il une manière plus élégante de faire cela avec 'grep' ?


...Trouver des fichiers d'un type donné

Comment puis-je localiser tous les scripts shell Bourne ou tous les fichiers texte dans mon répertoire Départ ?

Nous savons tous comment utiliser 'find' pour faire cela en se basant sur l'extension de fichier. Mais comment faire avec le contenu des fichiers, ce qui était requis par cette question ?

Utilisez la commande 'file' combinée avec 'find' et 'grep' :

% find . -print0 | xargs -0 file | egrep "(Bourne|Tenex)"
./sh:                Texte de script shell Bourne
./sh2:               Texte de script shell Bourne
./tsh:               Texte de script shell Tenex C

trouvera tous les scripts 'sh' et 'tcsh'. La magie est spécifiée par /etc/magic.


...Redémarrer un démon

Le Vendredi de la Semaine 45 nous donnait un script pour faire exactement cela. Il ne marche cependant pas toujours parce que quelques petits démons malicieux ajoutent des données à leur fichier .pid :

% sudo cat /var/run/sendmail.pid
11024
/usr/sbin/sendmail -L mta -bd -q30m

Changez le script pour utiliser 'head' au lieu de 'cat', de façon à couper les lignes supplémentaires :

...
sudo kill -HUP `head -n1 /var/run/$1.pid`
...

Editer plusieurs fichiers

Voir Semaine 50 pour les astuces précédentes sur vim.

Utilisez la commande 'new' pour séparer l'écran de façon à éditer plusieurs fichiers dans la même fenêtre Terminal.

:new

sépare l'écran en deux moitiés et crée un nouveau buffer d'édition, et :

:new file-1

sépare et lit 'file-1' dans le nouveau buffer d'édition.

Utilisez ctrl-WW (ou ctrl-W ctrl-W) pour basculer d'un buffer/fichier à l'autre.


Diviser l'écran verticalement

Vim peut aussi diviser la fenêtre verticalement, ce qui est utile pour comparer deux fichiers côte à côte.

:vert new [file-1]

séparera l'écran verticalement et lira optionnellement le fichier file-1 dans le second buffer.


Comparer deux fichiers

La commande :

% vimdiff file-1 file-2

va lancer vim avec deux fichiers, créer une séparation verticale et marquer toutes les différences entre les deux fichiers.

Autrement, si vous déjà êtes en train d'éditer file-1, utilisez :

:diffsplit file-2

ou

:vert diffsplit file-2

pour charger file-2 et voir les différences.


Edition par lot de plusieurs fichiers

La commande :

% vim f1 f2 f3 f4 f5

va faire en sorte que vim lise les cinq fichiers nommés et comence à éditer f1.

Pour se déplacer entre les fichiers, utilisez :

:n - prochain fichier de la liste
:prev - précédent fichier de la liste

:wn ou :wprev est nécessaire pour écrire les changements puis éditer le prochain fichier, si le fichier en cours a été changé.

Listez les buffers avec :

:buffers

et passez à un buffer spécifique (buffer 2, par exemple) avec :

:b2

Raccourcis de Vim

Pour ceux qui sont des habitués des raccourcis de vim, en voici quelques-uns qui peuvent être rajoutés à votre fichier .vimrc.

Merci à Mike Schienle

" Erreurs de typographie
ab  teh the
ab  pritn print

" Touches " Elles reposent sur des blocs marqués par a (début) et par b (fin)
" D supprime tout entre les marques a et b map D :'a,'bd
" Effacement P - place le buffer a à la position actuel du curseur map P :pu a
" Effacement Y - rassemble a-b dans le buffer a map Y :'a,'by a
" Etoile c - convertit en minuscule map *c :'a,'bs/<[A-Z]/l&/g
" Etoile C - convertit en majuscule map *C :'a,'bs/<[a-z]/u&/g

Variables de Réglage et d'Environment

Les astuces de cette semaine comparent des tâches ordinaires effectuées sous tcsh par rapport à sh/bash. Ce sera une référence pratique si, comme moi, vous passez sans arrêt de l'un à l'autre et mélangez souvent les syntaxes.

Comment régler les variables et les variables d'environnement :

tcsh                sh/bash
set var = value     % var=value
setenv ENV value    % ENV=value; export ENV

Sous bash (en plus de sh) les variables peuvent être déclarées et marquées comme étant exportées et/ou en lecture seule :

declare [-options] var=value
-r = lecture seule
-x = exportée (variable d'environnement)

% declare -rx ENV=cant_change

Redirection et Pipes

Pour tcsh :

  stdout             cmd >fn
  stderr             (>/dev/tty) >&fn2
  both               cmd >& fn
  both diff files    (cmd >fn) >&fn2
  stdin              cmd 

to append >> no clobber >!
pipe stdout cmd | cmd2 pipe both cmd |& cmd2

Pour sh/bash :

  stdout            cmd >fn
  stderr            cmd 2>fn
  both same file    cmd >fn 2>&1 (cmd &>fn - bash)
  both diff files   cmd >fn 2>fn2
  stdin

to append >>fn no clobber >|fn
pipe stdout cmd | cmd2 pipe both cmd 2>&1 | cmd2
close stdout cmd >&- close stderr cmd 2>&- close stdin cmd <&- open file cmd <>fn

Fichiers de démarrage

Les fichiers suivants sont exécutées lorsque le shell démarre en mode interactif et dans l'ordre donné. Les démarrages du shell de connexion ainsi que de non-connexion sont indiqués.

Shell de connexion tcsh :

% tcsh -l
/etc/csh.cshrc
/etc/csh.login
~/.tcshrc
~/.login

Shell de connexion bash :

% bash --login
/etc/profile
~/.bash_profile

Shell de non-connexion tcsh :

% tcsh
/etc/csh.cshrc
~/.tcshrc

Shell de connexion bash :

% bash
~/.bashrc

Constructions de Contrôle 1 (Choix)

Le langage de script de tcsh ressemble beaucoup au langage de programmation 'c' (d'où le 'c' de tcsh) alors que ce n'est pas le cas de sh/bash.

Construction 'if' :

#!/bin/tcsh
if ("$1" == "positive") then
  echo "Oui"
else if ("$1" == "negative") then
  echo "Non"
else
  echo "Peut-être"
endif

#!/bin/sh if [ "$1" = "positive" ]; then echo "Oui" elif [ "$1" = "negative" ]; then echo "Non" else echo "Peut-être" fi

Construction 'switch/case' :

#!/bin/tcsh
switch ("$1")
  case "positive":
    echo "Oui"
  breaksw

case "negative": echo "Non" breaksw
default: echo "Peut-être" breaksw endsw
#!/bin/sh case "$1" in "positive") echo "Oui" ;;
"negative") echo "Non" ;;
*) echo "Peut-être" ;; esac

Constructions de Contrôle 2 (Boucle)

Le langage de script de tcsh ressemble beaucoup au langage de programmation 'c' (d'où le 'c' de tcsh) alors que ce n'est pas le cas de sh/bash.

Boucles 'for' :

#!/bin/tcsh 
foreach word (hello goodbye au-revoir)
    echo $word
end

#!/bin/sh for word in hello goodbye au-revoir do echo $word done

Boucles 'while' :

#!/bin/sh
n=0
while [ ! $n = 10 ]
do
  echo $n
  n=$(expr $n + 1)
done

#!/bin/tcsh set n = 0 while ($n != 10) echo $n set n = `expr $n + 1` end

Fichiers curieusement intitulés

Si vous avez un nom de fichier qui ressemble à :

% ls Z* Z???

Il se peut qu'il contienne des caractères non-standard. Utilisez le complément par tabulation pour révéler le nom de fichier :

% ls Z
% ls Zb^D"

(Remarquez que les noms de fichier n'apparaissent pas aussi bizarre quand ils sont affichés dans votre navigateur)

Le fichier peut être renommé ainsi :

% mv Z
% mv Zb^D" z-file

Si la partie visible du nom de fichier n'est pas unique :

% ls d
DB)b^D"o#?b^B, DB4#^ Danger

alors l'astuce de Mardi pourra être appliquée....


Fichiers curieusement intitulés II

Suite de l'astuce de Lundi, si la partie visible du nom de fichier n'est pas unique :

% ls d
DB)b^D"o#?b^B, DB4#^ Danger

utilisez le n° inode pour identifier le fichier.

% ls -i 
 590795 Danger         579654 bvt           563546 page2.htm    578980 tvb
 590442 D???????????   560810 Cantata.txt   563547 page3.HTML   529632 users
 590441 D??#^
...

puis utilisez 'find' pour le renommer :

% find . -inum 590442 -exec mv {} D-file ;

Un petit coup de 'fsck'

Quelques fois, la réparation d'un disque peut aider à rendre les fichiers fantômes bizarres un peu plus solides.

Pour faire cela, démarrer votre machine en mode mono-utilisateur en maintenant pressées les touches Commande et S

Pour réparer le volume de démarrage, tapez :

# fsck -y

Pour réparer d'autres partitions, tapez :

# fsck_hfs -y /dev/disk0sX

où X représente le numéro de tranche (partition) identifié par :

% pdisk
tapez L
lisez le n° de partition dans la colonne de gauche au côté du nom de volume
tapez q pour quitter.

% mount -uw /
% reboot

Répertoires profondément imbriqués

Des commandes (telle que fsck) peuvent quelques fois échouer à cause de répertoires trop imrbiqués les uns dans les autres. De telles imbrications peuvent être créées par des scripts bogués.

Recherche ceci sur le système de fichier avec :

% sudo find / -mindepth 30

(pour trouver des imbrications à plus de 30 niveaux).


Corbeille récalcitrante

Si vous êtes incapable d'effacer un fichier ou de vider la corbeille, allez voir cet article dans le Learning Centre -> Comment vider une corbeille récalcitrante (en anglais).


Le Nom Executable

L'astuce de cette semaine améliore le tutoriel du Learning Centre sur le scripting, partie 8 et partie 9.

Notez que ces astuces sont pour des scripts 'sh' ou 'bash'.

Le paramètre spécial shell $0 contient le nom du script mais sous sa forme étendue avec le chemin d'accès. Pour n'afficher que le nom du script utilisez ${0##*/}

$ cat usage
#!/bin/sh
echo "Usage 1: $0"
echo "Usage 2: ${0##*/}"

$ ~/Development/test/usage
Usage 1: /Users/saruman/Development/test/usage
Usage 2: usage

Mac OS X Unix Tutorial 9 - Shell Scripting 2. New 8 Septembre.


Conditions Complexes

Les conditions dans les instructions 'if', 'elif' et 'while' peuvent contenir des éléments AND, OR et NOT. Par exemple, pour tester si le paramètre 1 est "-p" AND que ke paramètre 2 est vide, utilisez :

if [ "$1" = "-p" -a "$2" = "" ]; then

Le '-a' représente AND.

Utilisez '-o' pour OR.

Pour inverser une condition utilisez le point d'exclamation (!). Par exemple pour tester qu'un fichier n'est pas un répertoire :

if [ ! -d "$file" ]; then

Mac OS X Unix Tutorial 9 - Shell Scripting 2. New 8 Septembre.


Tester qu'un Volume est Monté

Pour tester qu'un volume est monté, par exemple /Volumes/your-user, il est nécessaire de vérifier que /Volumes/your-user existe AND qu'il est n'est pas un fichier ou un répertoire classique. Une façon de faire cela consiste à examiner la sortie de df :

mounted=$(df | grep "/Volumes/$USER")

Si le volume n'est pas monté alors la 'mounted' sera une chaîne vide. Notez que la variable d'environnement $USER correspond au nom court de l'utilisateur actuel.

On peut utiliser la condition :

if [ ! "$mounted" ]; then
  instruction pour monter /Volumes/$USER
fi

parce qu'une chaîne vide renvoi la valeur FALSE.

Mac OS X Unix Tutorial 9 - Shell Scripting 2. New 8 Septembre.


Monter un Volume AFP

Un volume AppleShare peut être monté avec les lignes suivantes :

mkdir /Volumes/$USER
mount_afp afp://$USER@carcharoth.mayo-family.com/$USER /Volumes/$USER > /dev/null

Cela monte le répertoire Départ de l'utilisateur actuel localisé sur le serveur 'SERVER' à l'endroit /Volumes/nom-court-utilisateur.

Par exemple, le script :

$ cat mount-user
#!/bin/sh

mounted=$(df | grep "/Volumes/$USER")
if [ ! "$mounted" ]; then echo "Mounting /Volumes/$USER" mkdir /Volumes/$USER mount_afp afp://$USER@your-server-address-here/$USER /Volumes/$USER > /dev/null else echo "/Volumes/$USER already mounted" fi

Montera mon répertoire Départ (saruman) localisé sur le serveur sous /Volumes/saruman :

$ ls /Volumes


$ ./mount-user
Mounting /Volumes/saruman

$ ls /Volumes
saruman

$ ./mount
/Volumes/saruman already mounted

Mac OS X Unix Tutorial 9 - Shell Scripting 2. New 8 Septembre.


Un Script de Montage Utilisateur

Voici un script qui utilise les astuces données cette semaine et les tutoriels de programmation shell du Learning Centre partie 8 et partie 9.

Il monte le répertoire départ de l'utilisateur en cours sur le serveur $SERVER, sur la machine locale au point de montage $AFP_MOUNT/$USER.

Il utilise deux variables d'environnement qui doivent être renseignées avant que le script ne démarre :

AFP_MOUNT pour indiquer où monter les volumes (en général '/Volumes')

SERVER pour l'adresse réseau du serveur

Un mot de passe peut être donné en option avec '-p password'. Sinon, mount_afp vous demandera votre mot de passe dans une pop-up ou le prendra dans le trousseau.

$ cat mount-user
#!/bin/sh

# monte le répertoire départ de l'utilisateur en cours # sur le serveur dans le répertoire afp de montage #
if [ ! "$1" = "" -a ! "$1" = "-p" ]; then echo "Utilisation : ${0##*/} [-p password]" echo " monte le répertoire départ de ${USER} echo " sur le serveur à $AFP_MOUNT/$USER" exit fi
if [ "$1" = "-p" -a "$2" = "" ]; then echo "Utilisation : ${0##*/} [-p password]" echo " donne un mot de passe" exit fi
# si le mot de passe est donné, ajoute ":" au début # pour être en conformité avec la syntaxe de montage if [ "$1" = "" ]; then pass="" else pass=":"$2 fi
# vérifie s'il est déjà monté # mounted=$(df | grep "$AFP_MOUNT/$USER")
# s'il n'est pas monté, s'assure que le point # de montage (répertoire) est disponible # if [ ! "$mounted" ]; then if [ ! -d $AFP_MOUNT/$USER ]; then if [ -e $AFP_MOUNT/$USER ]; then rm -f $AFP_MOUNT/$USER fi mkdir $AFP_MOUNT/$USER fi mount_afp afp://$USER$pass@$SERVER/$USER $ALM_AFP_MOUNT/$USER > /dev/null disktool -r fi
# retourne 0 si aucun montage n'a été effectué, 1 sinon # if [ ! "$mounted" ]; then exit 1 else exit 0 fi

Mac OS X Unix Tutorial 9 - Shell Scripting 2. New 8 Septembre.


Liens Symboliques

Un lien est un fichier qui 'pointe' vers un autre fichier. Il y en a deux variétés : les liens symboliques et les liens dures (voir Mardi).

Un lien symbolique est créé en utilisant la commande 'ln' en spécifiant l'option '-s' pour symbolique.

% echo "Je suis le fichier original" > orig-file
% /bin/ls -l *-file
lrwxr-xr-x 1 saruman staff  9 ... link-file -> orig-file
-rw-r--r-- 2 saruman staff 23 ... orig-file

Le lien symbolique est illustré par le premier caractère 'l' dans un long listing et comme pointant vers le fichier d'origine.

% cat orig-file
Je suis le fichier original
% cat link-file
Je suis le fichier original

'link-file' est tout simplement un fichier qui contient du texte décrivant le chemin d'accès absolu vers 'orig-file', et qui contient un indicateur paramétré pour dire "je suis un lien symbolique". Les deux fichiers peuvent être n'importe où sur le système de fichiers - répertoires différents, partitions, disques ou machines différentes.

Quand un 'link-file' est accédé, le lien est automatiquement suivi et résulte en l'accès de 'orig-file'.

Si 'orig-file' est déplacé ou renommé le lien est brisé.


Liens Durs

Un lien dur est créé par la commande 'ln' mais SANS spécifier l'option '-s'.

% ln orig-file hard-file
% /bin/ls -l *-file
-rw-r--r-- 2 saruman staff 23 ... hard-file
lrwxr-xr-x 1 saruman staff  9 ... link-file -> orig-file
-rw-r--r-- 2 saruman staff 23 ... orig-file 

% cat orig-file Je suis le fichier d'origine % cat hard-file Je suis le fichier d'origine

'hard-file' n'est pas un nouveau fichier mais une nouvelle entrée de répertoire qui pointe vers les données du fichier original (le même endroit sur le disque). En termes techniques, les deux entrées de répertoire font référence au même inode.

Les deux fichiers sont en fait les mêmes et il n'est pas possible de déterminer qui est l'original et qui est le lien dur.

Les deux fichiers peuvent être renommés ou déplacés sans briser le lien.

Les liens durs ne peuvent être créés pour des partitions ou des disques différents. Cela vient du fait que les inodes appartiennent à une partition particulière et ne sont pas uniques dans un ensemble de partitions ou de disques.


Alias

Un alias est géré par le Finder et n'est pas reconnu par Unix. Un Alias comporte un data fork vide avec les informations relatives à l'alias qui sont stockées dans le resource fork.

(Crée un alias vers orig-file en utilisant le Finder.)
% /bin/ls -l *-file
-rw-r--r-- 1 saruman staff  0 ... alias-file
-rw-r--r-- 2 saruman staff 23 ... hard-file
lrwxr-xr-x 1 saruman staff  9 ... link-file > orig-file
-rw-r--r-- 2 saruman staff 23 ... orig-file 

% cat orig-file Je suis le fichier d'origine % cat alias-file %

Unix ne voit que les data fork et considère les 'alias-file' comme étant vides. Le Finder reconnaît les liens symboliques et les liens durs. La copie d'un alias avec la commande Unix 'cp' ne créera qu'un fichier vide.

Remarquez que 'ls' avec l'option -s reconnaît le resource fork lors du calcul de blocs occupés par le fichier (blocs de 36k ou de moitiés de 72K).

% /bin/ls -sl *-file
72 -rw-r--r-- 1 saruman staff  0 ... alias-file
 8 -rw-r--r-- 2 saruman staff 23 ... hard-file
 8 lrwxr-xr-x 1 saruman staff  9 ... link-file > orig-file
 8 -rw-r--r-- 2 saruman staff 23 ... orig-file

Travailler avec les Liens

Beaucop de commandes acceptent des options qui affectent la manière dont elles traitent les liens — en général pour contrôler qu'elles doivent traiter le lien lui-même ou suivre le lien et traiter le fichier cible. Cela s'applique seulement aux liens symboliques.

On peut dire à 'ls' de suivre le lien avec l'option '-L':

% ln -s ~/Documents/Letters/Channel Dynamics a-letter
% /bin/ls -l a-letter
lrwxr-xr-x 1 saruman staff    49 ... a-letter >
 /Users/saruman/Documents/Letters/Channel Dynamics
% /bin/ls -lL a-letter
-rw-r--r-- 1 saruman staff 20480 ... a-letter

et elle peut montrer les numéros d'inode avec l'option '-i':

% ls -l i *-file 
678102 -rw-r--r-- 1 saruman staff  0 ... alias-file
678094 -rw-r--r-- 2 saruman staff 23 ... hard-file
678095 lrwxr-xr-x 1 saruman staff  9 ... link-file > orig-file
678094 -rw-r--r-- 2 saruman staff 23 ... orig-file

Remarquez que le lien dur et le fichier d'origine ont le même numéro d'i-node.

D'autres commandes acceptent les options '-H', '-L', et '-R' qui signifient en général :

-H Si l'option -R est spécifiée, les liens symboliques sont suivis
sur la ligne de commande. (Liens symboliques rencontrés dans
l'arbre transversal ne sont pas suivis.)

-L Si l'option -R est spécifiée, tous les liens symboliques sont suivis.
-P Si l'option -R est spécifiée, aucun lien symbolique n'est suivi.

Ces commandes sont les suivantes :

  • 'chflags'
  • 'chgrp'
  • 'chmod'
  • 'chown'
  • 'cp' HLP
  • 'du' HLP
  • 'find'

'test' (aussi connu sous '[') peut tester un lien symbolique avec '-L':

-L file - Vrai si le fichier existe et est un lien symbolique.

Faire un Répertoire Ombre

La commande 'lndir' crée un répertoire ombre de liens symboliques vers un autre répertoire.

Par exemple, construisez la structure suivante :

% mkdir ln-test
% cd ln-test
% touch a b
% mkdir c
% touch c/a c/b
% ls -R
.:
a b c

c:
a b

Faites un répertoire ombre :

% cd ../
% mkdir ln-test-copy
% cd ln-test-copy/
% lndir ../ln-test
../ln-test/c:

Examinez le répertoire ombre créé par 'lndir' :

% /bin/ls -lR
total 16
lrwxr-xr-x  1 saruman  staff   12 Oct  5 11:44 a -> ../ln-test/a
lrwxr-xr-x  1 saruman  staff   12 Oct  5 11:44 b -> ../ln-test/b
drwxr-xr-x  4 saruman  staff  136 Oct  5 11:44 c

./c: total 16 lrwxr-xr-x 1 saruman staff 17 Oct 5 11:44 a -> ../../ln-test/c/a lrwxr-xr-x 1 saruman staff 17 Oct 5 11:44 b -> ../../ln-test/c/b

Editer Plusieurs Fichiers

Si vous souhaitez éditer un groupe de fichiers, combinez le 'find' avec l'éditeur de votre choix ('vim' dans mon cas). Pour éditer tous les fichiers texte (*.txt) du répertoire courant, utilisez :

% vim `find . -iname "*.txt"`

Dans 'vim' ou 'vi', tapez

:n

pour passer au fichier suivant, ou

:wn

pour sauvegarder les changements et passer au fichier suivant.

Pour annuler les changements et passer au fichier suivant, utilisez :

:n!

Et enfin, pour quitter avant que la liste entière des fichiers ait été éditée :

:q!

Editer en Fonction du Contenu

Pour chercher tous les fichiers dont le nom correspond à un modèle de nom de fichier ET qui contiennent un texte particulier, utilisez ce qui suit.

Par exemple, pour chercher tous les fichiers texte (*.txt) qui contiennent le terme "memo", puis les éditer avec 'vim' :

vim `find . -type f -iname "*.txt" -print0 | xargs -0 grep -ilw "memo"`
  • Les options -print0 et -0 sont là pour venir à bout des noms de fichier contenant des espaces.
  • L'option -type f de 'Find' permet de s'assurer que seuls les fichiers habituels sont pris en considération.
  • Les options -iw de 'Grep' permettent de s'assurer que la recherche du texte s'effectue sans tenir compte de la casse et porte sur les mots en entier.

Editions avec Less

Si vous visualisez un fichier avec 'less', et que vous décidez ensuite de l'éditer, tapez juste 'v'. Cela vous emmenera dans l'éditeur 'vi', pré-chargé avec le fichier que vous êtes en train de consulter.

Si 'vi' n'est pas de votre goût, modifiez la variable d'environnement VISUAL de façon à définir l'éditeur qui sera utilisé.

% setenv VISUAL vim

Vous pouvez faire la même chose avec 'more', sauf que vous devrez modifier la variable d'environnement EDITOR à la place. Notez que 'less' utilisera EDITOR si VISUAL n'est pas définie.


Corruption...

Si votre session Terminal est corrompue, par exemple après avoir accidentellement édité ou affiché un fichier binaire, utilisez 'tput'.

% tput reset

pour faire un reset du Terminal, ou

% tput init

pour l'initialiser.

La difference entre les deux dépend repose sur la différence entre les chaînes 'reset' et 'init' du Terminal situées dans la base de données 'terminfo' (/usr/share/terminfo/....). Mac OS X utilise la terminfo plutôt que la termcap. Terminfo est une base de données compilée et pour pouvoir en voir le contenu vous devez utiliser 'infocmp terminal-name'.

Par exemple :

% infocmp vt100
% infocmp xterm

Nettoyage

Nettoyer un fichier avec 'tr' et 'sed'.

La commande suivante retire les espaces et les lignes blanches en trop et change les fins de ligne au format Mac en des fins de lignes au format Unix.

% tr -s " " < test.txt | tr \r \n | sed '/^$/d' > out.txt

Le fichier en entrée est test.txt et celui en sortie est out.txt


A propos des Expressions Régulières

Les 'RE' suivent trois tendances : le vieux style 'basique' ou 'obsolete' tel que reconnu par 'grep', 'sed', 'vi', ...; le style 'étendu' ou compatible-POSIX tel que reconnu par egrep, gawk, PHP, ...; et les expressions régulières Perl reconnues par Perl et PHP.

Perl est plus puissant que POSIX qui est à son tour plus puissant que le Basic.

Des incompatibilités existent entre les différentes variétés, tout un chacun devra donc vérifier quelle forme utilisée avec un utilitaire donné.

Par défaut, la recherche s'effectue ligne à ligne et est sensible à la casse.

Les astuces de cette semaine vont se concentrer sur les "RE" de style POSIX.


Correspondance et Echappement avec les 'ER' POSIX

% cat test
Ceci est un fichier test
pour illustrer l'utilisation des
expressions régulières.
Voici un symbôle $ dollar.
Ceci est la fin du fichier.

Pour rechercher une chaîne simple :

% egrep "Ceci" test
Ceci est un fichier test

Vous devez rendre explicitement la recherche insensible à la casse : la méthode dépendra de l'utilitaire que vous utilisez. Pour 'egrep' utilisez l'option -i.

Les caractères qui ont un sens spécial au sein des expressions régulières doivent être échappés pour dire "prend litéralement le caractère et ignore tout autre sens spécial qu'il pourrait autrement avoir".

Les caractères spéciaux qui doivent être échappés sont :

. ^ $ * + ? [ ( ) | {

Par exemple :

% egrep "$ dollar" test
(pas de correspondance)

% egrep '$ dollar' test
Voici un symbôle dollar $.

Utilisez des guillemets pour éviter que le shell interprête le signe $.

Notez qu'il n'est pas toujours nécessaire d'échapper les caractères spéciaux car ils peuvent n'être spéciaux que dans des contextes particuliers, mais il est quand même préférable de le faire tout le temps.

% egrep 'symbôle $ dollar' test
Voici un symbôle $ dollar.

Ancres

Une ancre est utilisée pour forcer le modèle à correspondre soit avec le début soit avec la fin d'une ligne.

% cat test
ceci est la ligne n° 1
et ceci est la deuxième ligne

La recherche de 'ceci' ou de 'ligne' retournera les deux lignes du fichier :

Utilisez '^' pour ancrer le modèle sur le début d'une ligne :

% egrep '^ceci' test
ceci est la ligne n° 1

Utilisez '$' pour ancrer le modèle sur la fin d'une ligne :

% egrep 'ligne$' test
et ceci est la deuxième ligne

Jokers et Répétiteurs

Le caractère spécial '.' correspondra à n'importe quel caractère.

Pour trouver bg utilisez :

% cat test
Ceci est un bag.
Ceci est un bug.
Ce buug ne sera pas trouvé.

% egrep "b.g" test
Ceci est un bag.
Ceci est un bug.

% egrep "b..g" test
Ce buug ne sera pas trouvé.

Ces caractères spéciaux précisent que le caractère précédent est répété un certain nombre de fois :

? cherche répété de 0 à 1 fois
+ cherche répété 1 ou plusieurs fois
* cherche répété 0 ou plusieurs fois

'zu?z' cherche 'zz' ou 'zuz'
'zu+z' cherche 'zuz' ou 'zuuz', 'zuuuzzzz'
'zu*z' cherche 'zz, 'zuz', 'zuuz', 'zuuu...z'

Enfin :

'Hello.*goodbye' correspondra à Hello<0 ou plusieurs caractères quelconques>goodbye

Rangées

Utilisez les rangées pour chercher un nombre spécifique de caractères.

'{m,n}' cherche répété de m à n fois
'{m,}' cherche répété m fois ou plus
'{m}' cherche répété m fois

'zu{3.5}z' trouve 'zuuuz', 'zuuuuz', 'zuuuuuz'
'zu{3,}z' trouve 'zuuuz', 'zuuuuz', 'zuuuuu...z'
'zu{4}z' trouve juste 'zuuuuz'

Rechercher une Série de Caractères

Les astuces de cette semaine sont la suite de la série initiée la semaine dernière sur les Expressions Régulières (ER) POSIX.

Rechercher n'importe quel caractère compris dans une série en utilisant une expression entre crochets (une série de caractères délimitée par []).

% egrep 'b[aeiou]g'

trouvera bag, beg, big, bog, et bug.

Inverser la recherche en commençant la séquence par le caractère '^'.

% egrep 'b[^aeiou]g' file

trouvera bbg, bcg, ... bzg, mais pas bag, beg, etc.

Rechercher une série de caractères consécutifs en utilisant un tiret comme dans [a-z] pour tous les caractères minuscules ou [0-9] pour les chiffres. Par exemple:

% egrep '^[a-zA-Z]{3}[0-9]{2}$' file

trouvera 'lettre lettre lettre chiffre chiffre' ancré au début et à la fin de la ligne (voir les astuces de la semaine dernière sur les ancres et les répétiteurs {}).


Classes de Caractères

Une classe de caractère est un nom appliqué à un ensemble particulier de caractères, enfermé dans :class-name: et utilisé dans une expression entre crochets.

[:alpha:] recherche tous les caractères alphabétiques
[:alnum:] recherche tous les caractères alphanumériques
[:alpha:?] recherche tous les caractères alphanubétiques ou un '?'.

Les classes sont :

alnum digit punct
alpha graph space
blank lower upper
cntrl print xdigit

Les classes de caractères fonctionnent en PHP et en Perl, mais ne semblent pas fonctionner avec egrep sous OS X 10.2.


Echappement ou Manque de cela

Il n'est pas nécessaire (en fait, c'est incorrect) d'échapper les caractères spéciaux ^ $ * + ? [ ( ) | { dans un expression entre crochets (voir astuce de Lundi).

Pour faire correspondre un '^' assurez-vous qu'il n'est *pas* le premier caractère de la liste (sinon, il inversera la correspondance) et pour faire correspondre ']' assurez-vous qu'il *est* le premier caractère de la liste.

% egrep '[]%$^]' file

correspond à un des ] % $ ^

Aucune correspondance avec ci-dessus avec :

% egrep '[^]%$^]' file

Notez qu'il est permis d'échapper des caractères spéciaux dans des expressions entre crochets en utilisant Perl ou des expressions compatibles Perl en PHP.


Tester des Expressions Régulières

La façon la plus simple de tester une expression régulière est d'utiliser 'egrep' et l'entrée standard.

% egrep ''

egrep lira l'entrée standard (aucun nom de fichier fourni). Tapez une ligne de texte. Si l'expression régulière correspond, la ligne de texte sera réaffichée, sinon elle ne le sera pas.


Visualisation des Fichiers Logs

Cette semaine et la semaine prochaine, je vais aborder ce qui concerne les fichiers logs, de leur consultation à la configuration du démon de logging.

La plupart des fichiers log résident dans '/var/log', y compris le fichier log principal du système et les fichiers logs des démons netinfo et lookup. Si vous avez activé des services mail, ftp et impression, vous verrez leur fichier log ici aussi. Les informations générales et critiques en rapport avec mail sont écrites dans le fichier log système.

Visualiser des fichiers log en utilisant 'tail' (system.log dans l'exemple), de façon statique en tapant :

% tail -n35 /var/log/system.log

'-n35' est utilisé pour montrer les 35 dernières lignes au lieu des 10 dernières par défaut.

Visualiser des fichiers log de façon dynamique en tapant :

% tail -n35 -f /var/log/system.log

Pressez control-c pour stopper 'tail' et revenir à la ligne de commande.

La commande :

% tail -n35 -f /var/log/system.log &
[1] 683 <--------------- notez le numéro qui est ici.

va constamment interrompre l'écran de votre Terminal avec les entrées les plus récentes du fichier log et va finir par vous irriter :-)

Pour l'arrêter, tapez :

% kill nnn

où nnn est le numéro que vous aviez noté précédemment.


zcat et tlog

Jetez un oeil dans /var/log. Vous remarquerez que les fichiers log sont archivés périodiquement : quotidiennement pour le fichier log système et hebdomadairement pour les autres. Cela se traduit par la création d'une archive à partir du fichier log le plus récent en .0.gz et par la création d'un tout nouveau fichier log vide. Les anciens fichiers log archivés sont de nouveau archivés - c'est à dire renumérotés 0->1, 1->2, etc, le plus anciens étant supprimés.

Vous pouvez visualiser les anciens fichiers log sans avoir à les décompresser et à les compresser de nouveau en utilisant 'zcat'.

% zcat /var/log/system.log.0.gz | tail -n35

Créez un alias afin d'avoir un raccourci pratique pour consulter les fichiers logs :

alias tlog 'tail -f -n35 /var/log/!:1.log'

permettant à quiconque de taper :

% tlog system

plutôt que :

% tail -n35 -f /var/log/system.log

Faites vos Archives

Si vous avez lancé 'apache', ou 'named' ou tout autre démon créant des fichiers log, vous pouvez les archiver (voir l'astuce de Mardi) vous-même avec un simple script placé dans /etc/weekly.local. 'apache' and 'named' écrivent leurs fichiers log dans un sous-répertoire de /var/log, et donc les fichiers log ne sont pas archivés par les scripts standard hebdomadaires.

Si /etc/weekly.local n'existe pas créez le tel quel :

4.0k -r-xr-xr-x 1 root wheel 973 Nov 1 14:01 weekly.local

Le script ressemblera à cela :

#!/bin/sh -

################################## # Local weekly tidy-up script # ##################################
host=$(hostname -s) echo "Subject: $host Local weekly run output"
for logtype in httpd named do
echo "" echo -n "Rotating type $logtype log files:"
if [ -d /var/log/$logtype ]; then cd /var/log/$logtype for log in *.log do echo -n " $log" if [ -f "${log}.3.gz" ]; then mv -f "${log}.3.gz" "${log}.4.gz"; fi if [ -f "${log}.2.gz" ]; then mv -f "${log}.2.gz" "${log}.3.gz"; fi if [ -f "${log}.1.gz" ]; then mv -f "${log}.1.gz" "${log}.2.gz"; fi if [ -f "${log}.0.gz" ]; then mv -f "${log}.0.gz" "${log}.1.gz"; fi if [ -f "${log}" ]; then mv -f "${log}" "${log}.0" /usr/bin/gzip -9 "${log}.0" fi touch "$log" done
case $logtype in httpd) apachectl graceful;; named) ndc restart;; *);; esac
fi
done
echo "" echo "Complete"

Notes :

Cette ligne spécifie le sous-répertoire de /var/log qui sera archivé :

for logtype in httpd named

Ces lignes redémarrent chaque démon pour être sûr qu'ils reconnaîtront le nouveau fichier log :

httpd) apachectl graceful;;
named) ndc restart;;

'ndc restart' peut ne pas fonctionner sous Panther car il utilise une version différente de 'bind' vers Jaguar.


La Console

Les messages d'erreurs et les messages critiques du noyau et de messagerie sont écrits sur la Console (certains vont aussi dans le fichier log système). La Console est un périphérique situé dans /dev/console, et tout ce qui y est écrit est envoyé vers le fichier /var/tmp/console.log.

Consulter la Console avec :

% tail -n35 /var/tmp/console.log

ou

% tail -n35 -f /var/tmp/console.log

Le log de la Console peut aussi être consulté avec Console.app située dans /Application/Utilities.


dmesg

Les messages log du kernel, en particuliers ceux provenant des pilotes de périphériques, sont écrits dans le buffer des messages système au lieu des fichiers log.

Consulter le buffer des messages système avec :

dmesg

Si vous avez des problèmes au démarrage ou des problèmes avec un périphérique, 'dmesg' pourra être une source intéressante pour obtenir des informations utiles au déboguage.


Le démoniaque Syslogd

Cette semaine, nous poursuivons sur le thème du logging initié semaine 61.

Les applications Unix effectuent des entrées log via le 'system logger' : 'syslogd'. Chaque entrée log porte sur des outils tels que 'mail', 'syslog', ou cron', et sur des niveaux allant de l'urgence au déboguage.

Syslogd filtre les messages et les dirige vers des fichiers log particuliers en fonction de leur provenance ou de leur niveau, et de sa propre configuration. (Voir Mardi.)

Les outils sont :

auth, authpriv, cron, daemon, kern, lpr, mail, mark, news, syslog, user, uucp et local0 jusqu'à local7

Les niveaux sont :

emerg, alert, crit, err, warning, notice, info et debug

Changer la Configuration de Syslogd

Le démon syslogd enregistre les messages en fonction de leur provenance et de leur niveau (voir Lundi) et de sa propre configuration située dans /etc/syslog.conf.

Changez ce qui est enregistré et où ce sera enregistré en modifiant /etc/syslog.conf. Redémarrez syslogd et les démons correspondants pour vérifier que les changements soient perçus. Redémarrez la machine si des changements plus importants sont effectués.

Chaque ligne consiste en une liste de paires "outil.niveau" et d'une destination. Toutes les entrées log qui incluent un outil listé et un niveau d'erreur correspondant ou supérieur seront envoyées vers la destination. '*' est un joker avec son sens habituel.


Se connecter à un autre Hôte

Pour envoyer les messages vers un autre hôte, utilisez @hostname comme destination donnée dans /etc/syslogd. L'hôte destinataire doit avoir un syslogd démarré avec l'option -u. Les messages log sont envoyés sur le port UDP 514.

Notez que cela représente une vulnérabilité pour une attaque extérieure compte tenu qu'un pirate pourrait écrire en continue dans vos fichiers log.


Tester le Log avec Logger

La commande 'logger' peut être utilisée pour enregistrer manuellement des messages log comprenant l'outil d'origine et la priorité. Cela est utile pour tester une nouvelle configuration de 'syslogd'.

Ecrivez dans le fichier log de mail avec le niveau 'info' :

logger -p mail.info Message log de test ici...

Diffuser un message d'urgence à tous les utilisateurs connectés :

logger -p user.emerg Urgence...

Changer le Logging de ftpd

Changez le schéma de logging du démon ftp (ftpd).

Tapez :

cat /etc/syslog.conf
~ % cat /etc/syslog.conf

*.err;kern.*;auth.notice;authpriv,remoteauth.none;mail.crit /dev/console *.notice;*.info;authpriv,remoteauth,ftp.none;kern.debug;mail.crit /var/log/system.log
# The authpriv log file should be restricted access; these # messages shouldn't go to terminals or publically-readable # files. authpriv.*;remoteauth.crit /var/log/secure.log
lpr.info /var/log/lpr.log mail.* /var/log/mail.log ftp.* /var/log/ftp.log netinfo.err /var/log/netinfo.log
*.emerg *

Remarquez la ligne :

ftp.*        /var/log/ftp.log

qui indique que pour l'outil ftp tous les niveaux (indiqué par "*") seront envoyés vers ftp.log.

Changez /var/log/ftp.log pour envoyer les messages vers un fichier différent.

Cette ligne :

*.notice;*.info;authpriv,remoteauth,ftp.none;kern.debug;mail.crit     /var/log/system.log

exclut spécifiquement les messages ftp du log système en spécifiant 'ftp.none'

Changez en 'ftp.*' pour faire en sorte que le démon enregistre les messages log dans le log système.

Cette ligne :

*.err;kern.*;auth.notice;authpriv,remoteauth.none;mail.crit     /dev/console

spécifie que les niveaux 'err' et supérieurs de tous les outils ('*') (incluant ainsi ftp) sont envoyés vers la console.

Le log de la console peut être visualisé par Console.app, ou en consultant /var/tmp/console.log.


Actif ou Passif

Les connexions ftp sont de deux sortes :

Actives - avec ce mode, le serveur contacte le client pour lui transférer des données. Le client doit avoir les ports appropriés ouverts dans son firewall.

Passives - avec ce mode, le client contacte toujours le serveur et n'a donc pas besoin de ports ouverts. Le mode passif est le mode par défaut.

Si vous souhaitez utiliser le mode actif, ou trouvez que le mode passif a tendance à raccrocher, oouvrez un port dans le firewall avec :

% sudo ipfw add 2300 allow tcp from any 20,21 to any 1024-65535 in

(Le numéro de rôle, 2300 dans cet exemple, ne doit pas entrer en conflit avec des numéros de rôle existants).

Cela autorisera votre client à utiliser le ftp actif mais ne transformera pas votre Mac en serveur ftp.


Le umask

Le umask par défaut (autorisations des fichiers créés) positionné par le démon ftp est 027, ce qui signifie qu'il n'y a pas de permissions en lecture pour les autres sur les fichiers que vous envoyez. Si vous souhaitez changer ceci, par exemple pour permettre à Apache d'accéder aux fichiers que vous avez chargés, paramétrez alors le umask :

ftp> site umask 022

Cela n'affecte que la session actuelle.


Un umask Permanent

La solution umask de Mardi affecte seulement la session ftp dans laquelle elle est utilisée. Pour un effet permanent, à chaque connexion, vous devez configurer le démon ftp.

Editez le fichier /etc/ftpd.conf (ou créez le) - vous devez le faire en étant l'utilisateur (super) root.

Ajoutez la ligne :

umask all 022

Debugging FTP

Le démon ftp envoie ses messages de log dans /var/log/ftp.log

Si vous souhaitez inclure des informations supplémentaires dans le fichie log alors relancez le démon ftp avec l'option -d.

Editez le fichier :

/etc/xinetd.d/ftp

et ajoutez le debug ou toute autre option sur la ligne

server_args = -l

Sécurité

Tout propriétaire de compte Unix peut se servir de ftp dans un serveur. Pour empêcher un utilisateur particulier de se servir de ftp ajoutez son nom de compte à :

/etc/ftpusers

Pour créer un utilisateur qui ne peut pas se connecter mais peut lancer ftp réglez son shell sur :

/sbin/nologin

et assurez-vous que ce shell est listé dans :

% cat /etc/shells
# Liste des shells acceptables pour (1).
# Ftpd ne permettra pas aux utilisateurs de se connecter s'ils n'utilisent pas
# un de ces shells.

/bin/bash
/bin/csh
/bin/sh
/bin/tcsh
/bin/zsh
/sbin/nologin

Enfin, pour stopper un utilisateur ftp dans son exploration de ce qui se trouve hors de son répertoire de départ, faites un 'chroot' sur eux. Ajoutez leur nom de compte à :

/etc/ftpchroot

Remarquez que cette fonction est cassée dans OS X 10.2. Une alternative consiste à installer un nouveau démon ftp tel qu'un pure ftp. Reportez à ce fil de discussion :

Comment installer un pur FTP

Periodic

La maintenance périodique du système est programmée par 'cron' (voir Semaine 33). Cron lance un programme appelé 'periodic' qui a la responsabilité de lancer les scripts de maintenance.

% cat /etc/crontab
...
#minute hour  mday  month  wday  who   command
# Run daily/weekly/monthly jobs.
15      3     *     *      *     root  periodic daily
30      4     *     *      6     root  periodic weekly
30      5     1     *      *     root  periodic monthly
...

Le script quotidien est lancé à 3:15 am.
Le script hebdomadaire à 4:30 le Samedi.
Le script mensuel est lancé à 5:30 le premier de chaque mois.

Votre Mac doit tounrer (ne pas être en sommeil) pour que ces scripts puissent être lancés.

Le produit de ces scripts peut être trouvé dans :

% ls /var/log/*.out
/var/log/daily.out /var/log/monthly.out /var/log/weekly.out

Maintenance Manuelle

Si votre Mac n'est pas éveillé à des heures matinales (voir l'astuce de Lundi), vous devrez lancer les scripts de maintenance manuellement. Cela se fait ainsi :

% sudo periodic daily
% sudo periodic weekly
% sudo periodic monthly

Autrement, éditez /etc/crontab et choisissez des heures durant lesquelles votre Mac sera actif.

Ou, servez vous du freeware MacJanitor

http://macupdate.com/info.php/id/5856

Faites le vous même

Si vous souhaitez ajouter vos propres taches de maintenance - quotidienne, hebdomadaire ou mensuelle - alors créez les fichiers suivants si nécessaire.

/etc/daily.local
/etc/weekly.local
/etc/monthly.local

Ce sont des scripts shell réguliers et sont lancés automatiquement, une fois créés, par les scripts quotidien, hebdomadaire et mensuel par défaut.


Configuration Périodique

Les scripts lancés par 'periodic' pour les taches de maintenance quotidiennes, hebdomadaires et mensuelles sont localiés dans :

# ls /etc/periodic/*
/etc/periodic/daily:
100.clean-logs 500.daily

/etc/periodic/monthly:
500.monthly

/etc/periodic/weekly:
500.weekly

Periodic peut être appelé avec un chemin d'accès complet vers un répertoire (au lieu des termes daily, weekly ou monthly), et il lancera tous les scripts situés dans ce répertoire.

Periodic est configuré par le fichier :

/etc/defaults/periodic.conf

Vous pouvez ajouter votre propre réglage et les placer dans le fichier :

/etc/periodic.conf

Reportez-vous à 'man periodic.conf' pour plus d'informations.


Un Exemple d'Archiveur de Log

Ce script peut être placé dans /etc/weekly.local. Il archivera de façon circulaire (nombre de fichiers constant, le plus ancien laissant place au plus récent), mieux que ne le fait le script quotidien standard. Le script standard n'archive que les fichiers *.log qui sont dans /var/log. Ce script fait la même chose pour des sous-répertoires tels que /var/log/httpd/*.log et /var/log/bind/*.log.

#!/bin/sh -

########################## # Script quotidien de nettoyage # ##########################
host=$(hostname -s) echo "Sujet: $host - rapport du lancement quotidien en local"
# liste les sous-répertoires à considérer, dans ce cas # /var/log/httpd and /var/log/named for logtype in httpd named do
echo "" echo -n "Archivage des fichiers log de type $logtype :"
if [ -d /var/log/$logtype ]; then cd /var/log/$logtype for log in *.log do echo -n " $log" if [ -f "${log}.3.gz" ]; then mv -f "${log}.3.gz" "${log}.4.gz"; fi if [ -f "${log}.2.gz" ]; then mv -f "${log}.2.gz" "${log}.3.gz"; fi if [ -f "${log}.1.gz" ]; then mv -f "${log}.1.gz" "${log}.2.gz"; fi if [ -f "${log}.0.gz" ]; then mv -f "${log}.0.gz" "${log}.1.gz"; fi
if [ -f "${log}" ]; then mv -f "${log}" "${log}.0" /usr/bin/gzip -9 "${log}.0" fi touch "$log" done
case $logtype in httpd) apachectl graceful;; named) ndc restart;; *);; esac
fi
done
echo "" echo "Fin de traitement"

Nom de fichiers avec des Espaces

Les noms de fichiers avec des espaces peuvent poser problèmes dans les scripts. (Voir semaine 51 pour des exemples.)

Lors du traitement de tous les fichiers d'un répertoire avec une boucle 'for', utilisez '*' au lieu de '`ls`'. Par exemple:

bash$ ls -1
file
file 2

bash$ for file in `ls`; do echo "File: $file"; done
File: file
File: file
File: 2

bash$ for file in *; do echo "File: $file"; done
File: file
File: file 2

Arithmétique

Bash évaluera une expression arithmétique enfermée par $((...))

bash$ n1=3; n2=4; n3=5
bash$ echo $n1 $n2 $n3
3 4 5

Cela ne marchera pas :

bash$ n="(($n1+$n2)*$n3)"
bash$ echo $n
((3+4)*5)

Mais cela marchera :

bash-2.05a$ n=$(( ($n1 + $n2) * $n3 ))
bash-2.05a$ echo $n
35

Ou alors, utilisez des $((...)) imbriqués :

bash$ n=$(( $(( $n1 + $n2 )) * $n3 ))
bash$ echo $n
35

Quelque chose à Déclarer

Bash permet à quelqu'un de 'déclarer' des variables shell. Un des avantages de telles déclarations tient dans le fait qu'on peut leur donner des attributs spécifiques.

Déclarez une variable en lecture seule :

bash$ declare -r pi=3.14
bash$ echo $pi
3.14
bash$ pi=20
bash: pi: readonly variable

Les variables peuvent aussi être marquées comme étant des entiers, auquel cas bash appliquera des évaluations arithmétiques sans l'aide de $((...)) (voir Mardi):

Cela marchera :

bash$ declare area1
bash$ area1=5*5
bash$ echo $area1
5*5

Mais en utilisant 'declare -i', cela marchera aussi :

bash$ declare -i area2
bash$ area2=5*5
bash$ echo $area2
25

Valeurs par Défaut des Paramètres

Supposez que vous souhaitiez appliquer la valeur de $1 à une variable si $1 est donné, ou une valeur par défaut dans le cas contraire.

Cela peut être accompli avec :

#!/bin/bash 
#positionne level à $1, ou à la valeur 5 si $1 n'est pas donnée
if [ "$1" == "" ]; then
  level=5
else
  level=$1
fi

Ou plus simplement :

level=${1:-5}

Utilisez Printf

La commande printf est beaucoup plus puissante que echo. Elle prend comme argument une chaîne de formattage et un ensemble d'arguments à afficher dans le contexte de cette chaîne de formattage.

Cette instruction affichera une ligne, indenté d'un nombre calculé de caractères, l'intitulé étant aligné à droite et la première valeur étant en rouge.

bash$ cat tst
#!/bin/bash
declare -r norm="33[00m" red="33[31m"
declare -i indent=${3:-4}
declare -i spacer=20-$indent

printf "%${indent}s%-${spacer}s${red}%7d,${norm}%7dn" " " "Valeurs:" $1 $2
bash$ tst 1234 5678 Valeurs: 1234, 5678
bash$ tst 1234 5678 8 Valeurs: 1234, 5678

Réglage du Prompt

La variable d'environnement PS1 contient le prompt primaire du shell bash.

Changez le avec, par exemple :

$ declare -x PS1="host=h$ "
host=saruman$

h est remplacé par le nom d'hôte jusqu'au premier '.'. $ est remplacé par '$' pour les utilisateurs normaux et par '#' pour root.

Cette exemple affichera le nom de l'utilisateur courant et l'heure actuelle en rouge :

$ declare -x PS1="e[31mu-Ae[0m$ "
saruman-10:56$

D'autres possibilités (tirées du manuel bash)

  a     un caractère clôche ASCII (07)
  d     date sous la forme "Jourdelasemaine Mois Date"
  e     un caractère ASCII d'échappement (033)
  h     le nom d'hôte jusqu'au premier `.'
  H     le nom d'hôte
  j     nombre de jobs actuellement gérés par le shell
  l     nom de base du terminal du shell
  n     nouvelle ligne
  r     retour charriot
  s     nom du shell, basename de $0 
  t     heure (0-23) au format HH:MM:SS
  T     heure (0-11) au format HH:MM:SS
  @     heure (0-11) au format am/pm
  A     heure (0-23) au format HH:MM
  u     le nom de l'utilisateur actuel
  v     la version de bash (ex : 2.00)
  V     version de bash, version+niveaudepatch
  w     le répertoire actuel de travail
  W     nom de base du répertoire actuel
  !     le n° de la commande dans l'historique
  #     nbre de fois que la commande a été tapée
  $     a # pour root , sinon a $
  nnn   caractère avec nombre nnn octal
  \     un backslash
  [     début de caractères non imprimables
  ]     fin de caractères non imprimables

Fichiers de Démarrage Bash

Créez un fichier nommé '.bash_profile' à la racine de votre répertoire départ. Ce fichier sera exécuté lorsque bash sera invoqué en tant que shell de connexion (lorsque vous démarrez une nouvelle session Terminal avec Terminal.app). Placez ici les réglages qui seront passés aux sous-shells - ex : paramétrez des variables d'environnement telles que PS1 (voir l'astuce de Lundi) et le PATH de recherche.

Ajoutez aussi la ligne :

. .bashrc

Cela exécutera le second fichier de démarrage.

Créez un second fichier nommé '.bashrc' à la racine de votre répertoire départ. Ce fichier sera exécuté lorsque shell sera invoqué comme shell de non-connexion (quand vous tapez 'bash' pour démarrer un sous-shell). Si vous avez ajouté la ligne '. .bashrc' à '.bash_profile', '.bashrc' sera alors excuté pour tous les shells (de connexion et de non-connexion) interactifs. Placez tous les autres réglages dans '.bashrc'.


Pushd et Popd

Si vous souhaitez changer temporairement de répertoire, et souhaitez revenir au répertoire d'origine, utilisez 'pushd' au lieu de 'cd'. 'pushd' passe au nouveau répertoire mais enregistre le répertoire d'origine. 'popd' retourne au répertoire d'origine.

Par exemple:

$ pwd
/Users/saruman
$ pushd /etc
/etc ~
$ pushd /var/log
/var/log /etc ~
$ pwd
/var/log
$ popd
/etc ~
$ pwd
/etc
$ popd
~
$ pwd
/Users/saruman
$

Plus d'Historique

Par défaut, une session Terminal enregistre les 500 dernières commandes dans son historique. Si vous avez l'habitude de laisser votre Terminal ouvert pendant de longues périodes et que vous souhaiteriez disposer de plus d'historique (disons 2000 commandes), ajoutez ceci au fichier '.bash_profile' (voir astuce de Mardi).

declare -x HISTSIZE=2000;

Il est judicieux d'augmenter la taille du fichier historique aussi.

declare -x HISTFILESIZE=2000;

Si vous avez plus d'une session Terminal ouverte alors pour empêcher l'écrasement du fichier historique par la dernière session, régler l'option de fusion d'historique dans '.bashrc'

shopt -s histappend

Cela fera en sorte que les hostoriques de différentes sessions seront fusionnés.


Ignorer la Casse

Si vous souhaitez que la fonction de remplissage automatique des noms de fichier ignore la casse, par exemple :

$ ls ~/doc

sera complété par :

$ ls ~/Documents/

alors, créez un fichier appelé '.inputrc' à la racine de votre répertoire départ et ajoutez la ligne :

set completion-ignore-case on

En plus, pour faire en sorte que la fonction de remplissage automatique liste immédiatement des alternatives (bash fait d'abord sonner une clôche) ajoutez la ligne :

set show-all-if-ambiguous on

Ouvrir des Fichiers et des Dossiers

Utilisez la commande 'open' pour simuler un double-clic dans le Finder.

Voici quelques exemples d'utilisation.

Ouvrir un dossier dans une fenêtre du Finder :

% open Sites

Ouvrir un document avec son application par défaut :

% open Sites/index.html

Ouvrir un document avec une autre application :

% open -a /Applications/Internet Explorer.app Sites/index.html

Ouvrir de multiples dossiers/documents/applications d'un seul coup :

% open *.html pic1.jpeg pic2.jpeg ...

Lancer des Applications

Lancer des applications GUI, à la fois Cocoa et Carbon, en utilisant 'open'.

Ouvrez une application :

% open /Applications/Safari.app

Lancer une application Cocoa manuellement, par exemple sans se servir d'open.

% /Applications/Safari.app/Contents/MacOS/Safari &

Le '&' placé à la fin de la commande va lancer Safari sous forme de process séparé vous permettant de continuer à utiliser le shell en cours.

Le lancement manuel peut être plus rapide dans des scripts. Il peut aussi être utilisé pour lancer de multiples copies d'une application là où le Finder (et 'open') ne le ferait pas.


Lancer des Applications en tant que Root

Utilisez la commande 'sudo' pour lancer une application en tant que root.

L'utilisation de 'sudo open' ne marchera pas, car 'open' est exécutée en tant que root mais pas l'application qu'elle lance. On doit la lancer manuellement (voir l'astuce de Mardi).

% sudo -b open /Applications/Clock.app/
% ps -auxc | grep "[C]lock"
saruman  2405   ...    0:00.57 Clock

(Clock est lancé sous l'utilisateur 'saruman', PAS sous root.)

% sudo -b /Applications/Clock.app/Contents/MacOS/Clock
% ps -auxc | grep "[C]lock"
saruman  2405   ...    0:00.72 Clock
root     2410   ...    0:00.36 Clock

(Le second Clock est exécuté sous root.)


Les Dangers de Sudo

Ne JAMAIS utiliser 'sudo', ou faire quoi que ce soit sous root, lorsque vous avez bu trop de bières. Cela s'applique particulièrement à aujourd'hui :-)

Joyeux Noël.


Applications Carbon

Lancez une application Carbon manuellement (dans cet exemple, Internet Explorer).

% /System/Library/Frameworks/Carbon.framework/Versions/
Current/Support/LaunchCFMApp /Applications/
Internet Explorer.app/Contents/MacOS/Internet Explorer &

(Notez qu'il n'y a pas de retour-charriot dans cette commande)

Les applications Carbon ne sont pas dans le format binaire correct pour Mac OS X. Elles doivent être lancées par 'LaunchCFMApp', qui s'occupe de la magie nécessaire.

Sur les systèmes antérieurs à Panther, vous pouvez remarquer que l'utilisation de l'option '-c' avec la commande 'ps' affiche LaunchCFMApp à la place de l'application elle-même. Cela provoque l'échec de scripts et de commandes telles que 'killall'.

Lancer une Application Carbon en tant que root en utilisant :

% sudo echo
% sudo -b /System/Library/Frameworks/Carbon.framework/Versions/
Current/Support/LaunchCFMApp /Applications/
Internet Explorer.app/Contents/MacOS/Internet Explorer &

La ligne 'sudo echo' contourne les problèmes de saisie de mot de passe.


Valeurs par défaut

Les astuces de cette semaine s'appliquent à la fois aux paramètres de script bash tels que $1 et aux variables shell telles que $my_var. Dans les exemples de code, j'ai utilisé une variable shell.

Positionner la valeur d'une variable shell soit sur celle d'une autre variable ou paramètre, soit sur celle par défaut si l'autre variable ou paramètre n'est pas positionné.

$ echo $test
/hello/world

$ echo ${test:-not-set}
/hello/world

J'ai utilisé 'echo' pour illustrer l'extension, mais on devrait normalement l'assigner à une variable :

$ var=${test:-not-set}

Dans le prochain exemple, la variable 'test2' n'est pas positionnée et donc la valeur par défaut s'y substitue.

$ echo ${test2:-not-set}
not-set
$ echo $test2

Notez que test2 reste non positionnée jusqu'à ce qu'on utilise ':=' à la place de ':-'.

$ echo ${test2:=not-set}
not-set
$ echo $test2
not-set

Erreur sur Variables sans Valeur

Faites en sorte que bash rapporte une erreur si une variable ou un paramètre n'a pas de valeur.

$ echo ${test3:?}
bash: test3: parameter null or not set

Ecrivez un message d'erreur personnalisé avec :

$ echo ${test3:?it is not set}
bash: test3: it is not set

Une erreur est rapportée si une variable n'existe pas, comme ci-dessus, ou est valorisé à null (rien) :

$ test4=
$ echo ${test4:?}
bash: test4: parameter null or not set

Trancher

Prenez une tranche d'une variable.

$ echo $test
/hello/world

$ echo ${test:4}
lo/world

$ echo ${test:4:2}
lo

Le premier exemple extrait une tranche à partir du cinquième caractère (le premier étant le caractère 0) et le second extrait deux caractères à partir du cinquième.

Déterminez le nombre de caractères de la valeur d'une variable.

$ echo ${#test}
12

Tronçonner

Tronçonner la tête ou le pied d'une variable.

$ echo $test
/hello/world

Cet exemple recherche un modèle à partir du début de la variable ("/hell") et le tronçonne à partir de là :

$ echo ${test#/hell}
o/world

Il est permis d'utiliser des jokers "*" pour faire correspondre 0 ou plus d'occurences de n'importe quel caractère.

$ echo ${test#*l}
lo/world

Dans l'exemple précédent la chaîne la plus petite qui correspond à '*l' a été tronçonnée ('/hel'). Dans le suivant, l'utilisation d'un double # correspond à la chaîne la plus longue ('/hello/worl').

$ echo ${test##*l}
d

Extrayez juste le nom du script à partir du nom complet contenu dans le paramètre 0. Cela devrait être effectué dans un script bash.

En supposant que $0 est /usr/local/bin/script

scriptname=${0##*/}
echo $scriptname

donne :

script

Utilisez % à la place de # (et %% à la place de ##) pour tronçonner à partir de la fin de la chaîne.

$ echo ${test%/*}
/hello

$ echo ${test%%/*}
(empty string)

Cherche et Remplace

Chercher et remplacer une valeur dans une variable.

Pour chercher la première occurence de 'hello' et la remplacer par 'goodbye':

$ echo $test
/hello/world

$ echo ${test/hello/goodbye}
/goodbye/world

Pour remplacer toutes les occurences d'un modèle, utilisez '//'.

$ echo ${test/l/L}
/heLlo/world
$ echo ${test//l/L}
/heLLo/worLd

Utilisez # pour ancrer le modèle au début de la chaîne et % pour l'ancrer à la fin.

$ echo ${test2/#d/D}
ldld
$ echo ${test2/%d/D}
ldlD

Recherche Basique

Voir dans les semaines précédentes les astuces sur vim.

Rechercher dans un fichier un texte en particuler, tel que 'transform'. En mode normal (pressez la touche echappement pour sortir du mode insertion) type:

/transform

Si vous avez besoin d'une recherche sur un mot complet, de façon à ce que 'transformations' ne soit pas retenu, tapez :

/

Pour rechercher en arrière, utilisez :

?transform

Pour rechercher l'occurence suivante, tapez 'n' et 'N' pour la précédente.

Pour rappeler une précédente recherche, tapez '/' puis pressez la touche "flèche vers le haut" jusqu'à tomber sur la chaîne à rechercher.


Rechercher et Remplacer

Remplacer une erreur de frappe telle que 'teh' par 'the' en utilisant "chercher et remplacer" :

:%s/teh/the/g

'%' veut dire toutes les lignes du fichier et 'g' veut dire toutes les occurences de chaque ligne.

Remplacer '%' par une rangée d'adresse telle que '.,$' qui effectue le remplacement à partir de la ligne courante (ligne .) jusqu'à la fin du fichier (ligne $).

Pour rappeler un précédent rechercher-remplacer tapez "/" et pressez la touche "flèche vers le haut" jusqu'à atteindre l'occurence souhaitée.

Utilisez des expressions régulières dans les recherches vim. Voir semaines 59 et 60 pour plus d'informations sur les expressions régulières.

Chercher une ligne commençant par 'The' :

/^The

Remplacer 'chapter includes' par 'Section Contains:' :

:%s/[C|c]hapter (.*) [I|i]ncludes/Section 1 Contains:/g

La construction (...) capture le texte placé dans le modèle, tandis que 1 le rejoue dans dans la chaîne remplacée.


Personnaliser la Recherche

Rendez les recherches sensibles à la casse avec :

:set ignorecase

Maintenant, le modèle /the marchera pour The, the et THE

Avec "smartcase", les modèles entièrement en minuscule s'applique de manière insensible à la casse, tandis que les modèles comprenant des majuscules s'appliquent en étant sensible à la casse :

:set smartcase

Le modèle /the marche pour The, the et THE
mais le modèle /The ne marche que pour The

Mettez en évidence toutes les occurences trouvées en tapant :

:set hlsearch

et désactivez la mise en évidence avec :

:set nohlsearch

et utilisez :

:noh[ighlight]

pour désactiver temporairement la mise en évidence actuelle.


Recherche Rapide

Trouver l'occurence suivante du mot qui se trouve sous le curseur. En mode normal tapez '*' ou '#' pour rechercher vers le haut. Seules les mots entiers seront trouvés à moins que vous n'utilisiez 'g*' ou 'g#'.

Pour rechercher la prochaine occurence tapez 'n' et 'N' pour la suivante.


Recherche et Edition

Utilisez des commandes globales pour rechercher les lignes à éditer. Pour effectuer un 'Rechercher Remplacer', seulement sur les lignes qui commencent par 'edit', utilisez :

:g/^edit/s/hello/Goodbye/g

La forme générale de cette commande est :

g/search-pattern/command

'search-pattern' est une expression régulière et 'command' est une commande 'ex'. la forme est identique à celle utilisée par 'sed'.

Pour plus d'informations sur les commandes disponibles, utilise :

man ex

Pour supprimer toutes les lignes qui commencent par '.', utilisez :

:g/^./d

La commande 'd' supprime la ligne.

Pour sélectionner toutes les lignes qui ne correspondent pas au modèle, utilisez 'g!' au lieu de 'g'.

Pour utiliser les commandes du mode normal de vim à la place des commandes 'ex', utilisez :

g/search-pattern/normal vim-command-list

Cet exemple ajoutera '...' à toutes les lignes qui contiennent 'edit'

:g/edit/normal A...

La Commande File

Déterminez le type d'un fichier, de part l'analyse de son contenu, en utilisant la commande 'file' :

$ file ~/bin/*
add-user:             Bourne-Again shell script text
dhup:                 Bourne shell script text
crontab:              ASCII text
nodif:                Tenex C shell script text
test:                 Mach-O executable ppc
$ file ~/sites/.../*
data:        directory
images:      directory
include:     directory
index.php:   C++ program text   NOT QUITE!
java-script: directory
jf.html:     HTML document text
tc.html:     HTML document text

Utilisation de la Commande File

Utilisez la commande 'file' en association avec d'autres commandes pour filtrer les types de fichier.

$ find . -print0 | xargs -0 -n1 file
./important-info: directory
./important-info/mac-todo.txt: English text
./important-info/Packing List.rtf: Rich Text Format data, ...

Voir semaine 48, Vendredi en particulier.

Filtrez tous les fichiers au format texte riche en utilisant grep :

$ find . -print0 | xargs -0 -n1 file | grep -i "rich text"
./important-info/contact-info.rtf: Rich Text Format data, version 1, Apple Macintosh
./important-info/PW.rtf: Rich Text Format data, version 1, Apple Macintosh
./Job/CV.rtf: Rich Text Format data, version 1, Apple Macintosh

Extraction de Noms de Fichier

Apportez de la précision à l'exemple de Mardi pour n'afficher que les noms de fichiers :

$ find . | xargs -n1 file | grep -i "rich text" | awk '{print $1}'
./important-info/contact-info.rtf:
./important-info/PW.rtf:
./Job/CV.rtf:

Pour retirer le ':', dites à awk que le séparateur de champ est ':' :

$ find . | xargs -n1 file | grep -i "rich text" | awk -F: '{print $1}'
./important-info/contact-info.rtf
./important-info/PW.rtf
./Job/Adrian-Maio-CV.rtf
./Job/job-search.rtf

Enfin, éditez touts les fichiers au format texte riche :

$ open -a textedit $(find . | xargs -n1 file | grep -i "rich text" | awk -F: '{print $1}')

Dans le shell tcsh utilisez les apostrophes - `find ...` au lieu de $(find ...) .


La Commande Hexdump

Utilisez la commande 'hexdump' pour afficher le contenu d'un fichier binaire ou d'un fichier qui contient des caractères non affichables :

$ hexdump -n32 test
0000000 6109 6201 630a 6e6f 7720 736f 6d65 2074
0000010 6578 7420 616e 6420 7461 6273 2020 0a0d

Le fichier est affiché en hexadecimal, en se limitant aux 32 premiers octets (-n32).

On peut afficher en format caractère, avec les caractères non affichables soit en octal soit échappés (t = tab)... :

$ hexdump -n32 -c test
0000000 a t b 001 c n n o w s o m e t
0000010 e x t a n d t a b s n r

...ou en caractère hexadecimal plus, avec des caractères non affichables représentés par un point :

$ hexdump -n32 -C test
00000000 61 09 62 01 63 0a 6e 6f 77 20 73 6f 6d 65 20 74 |a.b.c.now some t|
00000010 65 78 74 20 61 6e 64 20 74 61 62 73 20 20 0a 0d |ext and tabs ..|

Essayez ceci :

$ hexdump -n4 /bin/*

La Commande String

Recherchez du texte ASCII dans un fichier binaire en utilisant la commande 'strings'.

a$ strings -a -16 /bin/ls
__dyld_mod_term_funcs
__dyld_make_delayed_module_initializer_calls
The kernel support for the dynamic linker is not present to run this program.
$NetBSD: cmp.c,v 1.14 1998/10/09 02:00:39 enami Exp $
@(#) Copyright (c) 1989, 1993, 1994
The Regents of the University of California. All rights reserved.
$NetBSD: ls.c,v 1.31 1998/08/19 01:44:19 thorpej Exp $
1ACFLRSTWacdfgiklnoqrstuxv
%s: directory causes a cycle
$NetBSD: print.c,v 1.22 1998/07/28 05:15:47 mycroft Exp $
%s %*u %-*s %-*s
$NetBSD: stat_flags.c,v 1.6 1997/07/20 18:53:12 christos Exp $
$NetBSD: util.c,v 1.15 1998/07/28 05:31:25 mycroft Exp $
usage: ls [-1ACFLRSTWacdfgiklnoqrstux] [file ...]
@(#)PROGRAM:ls PROJECT:file_cmds-60 DEVELOPER:root BUILT:Sun Jul 14 03:44:11 PDT 2002

'strings' recherche dans un fichier binaire des séquences de caractères affichables et les affiche. La longueur minimum par défaut est 4 mais elle peut être remplacée comme dans cet exemple. (option -16). Option -a recherche dans toutes les sections du fichier (par exemple, les fichiers exécutables ont des séctions pour le code et pour les données).


Options Shell

Utilisez la commande 'shopt' pour régler les options shell.

Pour régler :

$ shopt -s

Pour enlever le réglage :

$ shopt -u

Pour lister :

$ shopt

Quelques options utiles sont indiquées ci-dessous.

(1) Utilisez 'cdspell' pour corriger les erreurs mineures de frappe dans les noms de fichier passés à 'cd':

$ cd Dekstop
bash: cd: Dekstop: No such file or directory

Maintenant, réglez l'option shell 'cdspell':

$ shopt -s cdspell
$ cd Dekstop
Desktop

(2) Créez de courts alias pour de longs noms de répertoire :

$ shopt -s cdable_vars
$ cal="/Users/saruman/Sites/calendar"
$ cd cal
/Users/saruman/Sites/calendar

Note : n'utilisez pas l'alias '~' dans des variables 'cdable'.


Plus d'Options

Suite de l'astuce de Lundi :

(3) Autoriser le 'globbing' sensible à la casse :

$ ls -d d*
ls: d*: No such file or directory

Maintenant, autoriser la non sensibilité à la casse :

$ shopt -s nocaseglob
$ ls -d d*
Desktop Development Documents

(4) Incluer des fichiers point dans le 'globbing' :

$ ls -d *
Desktop     Documents  Movies   Pictures   Sites   osxfaq
Development Library    Music    Public     bin

Maintenant, autoriser le 'globbing' point :

$ shopt -s dotglob
$ ls -d *
.DS_Store     .dir_colors    .mplayer      Desktop
.FBCIndex     .emacs.d       .my.cnf       Development
.gimp-1.2     .mysql_history Documents     .gvimrc
...

(5) Autoriser l'extension des chemins d'accès améliorés. En temps normal, seuls '*', '?' et '[...]' sont reconnus (comme dans 'ls *' ou 'ls file.???').

$ shopt -s extglob

Le globbing étendu suivant est autorisé :

?(pattern-list) Recherche 0 ou 1 occurrence des modèles donnés
*(pattern-list) Recherche 0 ou plusieurs occurrences des modèles donnés
+(pattern-list) Recherche 1 ou plusieurs occurrences des modèles donnés
@(pattern-list) Recherche exactement un des modèles donnés
!(pattern-list) Recherche tout sauf un des modèles donnés

Commandes au Prompt

Faites en sorte que bash exécute une commande avant qu'il ne renvoit un prompt.

Pour afficher la date avant avant chaque prompt :

$ declare -x PROMPT_COMMAND='date'
Mon Feb 2 12:02:41 GMT 2004
$

Ecrivez un message dans la barre de titre de la fenetre du Terminal (dans cet exemple, la sortie de la commande date) :

$ declare -x PROMPT_COMMAND='echo -n "^[]0; $(date)^G"'

Notes :
^[ = échappement, obtenu en tapant contrôle-V puis escape.
^G = contrôle G, obtenu en tapant contrôle-V contrôle-G.

Cela fonctionne pour xterm et le Terminal d'Apple

Cela peut être utile :

$ declare -x PROMPT_COMMAND='echo -n "^[]0; $TITLE^G"'
$ declare -x TITLE="Hello"

Maintenant, toute commande ou script exécuté peut afficher quelque chose dans la barre de titre en positionnant la variable d'environnement TITLE.


Alias Avec Paramètres

A l'inverse de tcsh, les alias bash n'acceptent pas les paramètres. Cela vient du fait que bash prodigue un mécanisme plus puissant de part des fonctions.

Ecrivez une fonction appelée 'word' qui effectue une recherche dans le dictionnaire Webster situé /usr/share/dict.web2 :

$ function word () { grep $* /usr/share/dict/web2; }

$ word apple
apple
appleberry
appleblossom
applecart
appledrane
applegrower
applejack
...

$* s'applique à tous les paramètres passés à la fonction 'word'. $1 s'applique au paramètre 1, etc.

Pour lister toutes les fonctions, utilisez :

$ declare -f

Développer la Commande 'alias'

Si vous souhaitez que la commande 'alias' liste toutes les fonctions (voi l'astuce de Jeudi), déclarez cette fonction :

function alias ()
{
    if [ -z $* ] ; then
        builtin alias;
        declare -f;
    else
        builtin alias $* ;
    fi
}

(Cette astuce provient d'un message posté par Kenneth dans le Learning Centre forum.)


Document Céans Basique

Redirigez le texte vers l'entrée standard en utilisant les Documents Céans.

$ cat hd
#!/bin/bash

echo "Test"

cat <
Salut à tous.
Ce texte est le résultat
d'un "Document Céans"
EOD

echo "Fin"

La section entre '< $ ./hd
Test
Salut à tous.
Ce texte est le résultat
d'un "Document Céans"
Fin
$

Tout mot peut être utilisé comme délimiteur 'HereDoc', et la dernière ligne ne doit contenir que ce mot sans espace après.


Interprétation de Variables

Contrôlez l'extension d'une variable au sein d'un document céans.

Les variables shell au sein d'un document HereDoc sont interprétées comme d'habitude :

$ cat hd
#!/bin/bash

today=$(date)

cat <
Salut à tous. Nous sommes le $today.
EOD

$ ./hd
Salut à tous. Nous sommes le Mon Feb 16 11:53:46 GMT 2004.
$

Mais si le délimiteur est entouré d'apostrophes, aucune interprétation de variable n'est effectuée :

$ cat hd
#!/bin/bash

today=$(date)

cat <<'EOD'
Salut à tous. Nous sommes le $today.
EOD

$ ./hd
Salut à tous. Nous sommes le $today.
$

Supprimer l'Indentation

Supprimez l'indentation des scripts shell dans les textes HereDoc.

Les scripts élaborés comportent généralement des instructions indentées et il est naturel d'utiliser l'indentation. Pour permettre aux documents HereDoc de suivre une indentation naturelle, sans inclure de caractère tabulation dans le texte, utilisez '<<-'.

$ cat hd
#!/bin/bash

if [ "$1" = "" ]; then cat <<-EOD Hello there. Today is $(date). EOD fi
$ ./hd Hello there. Today is Mon Feb 16 12:08:16 GMT 2004. $

Malheureusement, cela ne marche pas pour les scripts indentés par des espaces.


Lire des Données

Utilisez un HereDoc et une fonction pour positionner des variables.

$ cat hd
#!/bin/bash

read_data ()
{
read make
read model
read colour
}

read_data <
BMW
3 series
Blue
HEREDOC

echo "Make: $make, model: $model, colour: $colour"

$ ./hd
Make: BMW, model: 3 series, colour: Blue
$

Commentaires / Variables de Test

Merci à Ian Ferguson pour l'astuce de Vendredi.

Utilisez des HereDocs pour commenter du code, évitant ainsi d'ajouter des "#" au début de chaque ligne :

$ cat hd
#!/bin/bash

echo "avant" :<<'EOD' if [ "$1" = "" ]; then echo "Aucun paramètre passé" fi EOD echo "après"
$ ./hd avant après $

Ici, l'instruction 'if' a été commentée.

Utilisez des HereDocs pour afficher un message d'erreur si une variable n'est pas positionnée :

$ cat hd
#!/bin/bash

var1=hello

: <
${var1?} ${var2?}
ERRORIFNOTSET

$ ./hd
./hd: var2: paramètre nul ou non positionné
$

Traitement des Extensions

Renommer un groupe de fichiers en une seule commande.

Cela *ne* marchera *pas* :

$ mv *.html *.php
usage: mv [-fi] source target
       mv [-fi] source ... directory

Le script suivant, appelé 'ext' pour 'basé sur l'extension', vous permettra d'y arriver :

$ cat ext
#!/bin/bash
shopt -s nullglob
for file in *.$2; do
$1 "$file" "${file%.$2}.$3"
done

Utilisez 'ext' comme suit pour renommer (mv) *.html de façon à obtenir une extension du type .php :

$ ext mv html php

Utilisez toute commande similaire, telle que 'cp', dans le script 'ext'.

Ajoutez une vérification de paramètre dans le script :

$ cat ext
#!/bin/bash

if [ "$3" = "" ] || [ "$4" != "" ]; then echo 'For each file *.ext1, executes "command file.ext1 file.ext2"' echo ' eg "cp html php" pour copier tous les fichiers html en équivallents php' echo ' "mv html php" pour renommer tous les fichiers html et leur attribuer une extension php' echo "Usage: ${0##*/} command ext1 ext2" exit fi
# cette option permet de retourner null et non *.$2 si aucun fichier ne correspond à *.$2 shopt -s nullglob
for file in *.$2; do $1 "$file" "${file%.$2}.$3" done

Traitement Récursif des Extensions

Renommer un groupe de fichiers de manière récursive en n'utilisant qu'une seule commande. Le script 'rext' fait la même chose que celui de l'astuce de Lundi sauf qu'il applique la commande à tous les fichiers sélectionnés dans la hiérarchie du répertoire. Il utilise le script 'ext'.

$ cat rext
#!/bin/bash
for dir in $(find . -type d); do
  pushd $dir > /dev/null
  ext $1 $2 $3
  popd > /dev/null
done

Utilisez 'rext' comme suit pour copier (cp) *.php en leur équivallent avec l'extension .html :

$ rext cp php html

Utilisez toute commande similaire, telles que 'mv', avec le script 'rext'.

Ajoutez une gestion de paramètre au script :

$ cat rext
#!/bin/bash

if [ "$3" = "" ] || [ "$4" != "" ]; then echo 'Exécute "command file.ext1 file.ext2" sur les fichiers trouvés ' echo ' dans la hiérarchie du répertoire' echo ' eg "cp html php" pour copier tous les fichiers html en leur équivalents php' echo ' "mv html php" pour changer tous les fichiers html en fichiers php' echo "Usage: ${0##*/} command ext1 ext2" exit fi
for dir in $(find . -type d); do pushd $dir > /dev/null ext $1 $2 $3 popd > /dev/null done

Traiter Plusieurs Fichiers

Si vous avez un script ou une commande qui soit incapable de prendre une liste de fichiers, utilisez le script 'each' pour simuler cela. 'each' exécute la commande donnée une fois par fichier.

$ cat each
#!/bin/bash
filetype=$1
shift

for file in $filetype; do $* "$file" done

Utilisez le script ainsi pour appliquer 'my-script' à tous les fichiers .html du répertoire courant :

$ each *.html my-script -options ...

Ajoutez une gestion de paramètre au script :

$ cat each
#!/bin/bash

if [ "$2" = "" ]; then echo "Exécute une commande sur tous les fichiers correspondants" echo "du répertoire courant" echo "Usage: ${0##*/} filetype commande-à-exécuter" exit fi
filetype=$1 shift
for file in $filetype; do $* "$file" done

Traiter Plusieurs Fichiers de Manière Récursive

Le script 'reach' fait la même chose que le script de Mercredi, sauf qu'il exécute la commande donnée sur tous les fichiers correspondants de la hiérarchie du répertoire.

$cat reach
#!/bin/bash
filetype=$1
shift
find . -name "$filetype" -print0 | xargs -0 -n1 $*

Utilisez le script ainsi pour appliquer 'my-script' à tous les fichiers .php situés dans la hiérarchie du répertoire :

$ reach *.php my-script -options ...

Ajoutez une gestion de paramètres au script :

% cat reach
#!/bin/bash

if [ "$2" = "" ]; then echo "Exécute une commande sur tous les fichiers correspondants" echo "de la *hiérarchie du répertoire" echo "Usage: ${0##*/} filetype commande-à-exécuter" exit fi
filetype=$1 shift find . -name "$filetype" -print0 | xargs -0 -n1 $*

Extension Sed

Créer une simple enveloppe pour la commande 'sed' (ou toute autre commande similaire) pour lui permettre de traiter directement un fichier. Normallement, sed utilise les sorties et entrées standard, et ne peut écrire dans son fichier entrée.

$ cat sedx
#!/bin/sh
tmp=tmp-file-for-$PPID
{    sed "$1" "$2" > $tmp 
  && mv $tmp "$2"
} || rm $tmp  

Notez que la ligne la plus évidente :

sed "$1" "$2" > $tmp ; mv $tmp "$2"

ne doit pas être utilisée ainsi compte tenu qu'une erreur dans le script sed provoquerait l'élimination de tous les fichiers.

Utilisez sedx de cette manière :

$ sedx 's/XXX/ZZZ/' index.html

pour appliquer la commande sed à index.html.

Le script tel qu'il est donné n'accepte qu'un seul fichier en entrée. Utilisez les scripts de Mercredi et de Jeudi pour traiter plusieurs fichiers.

S'applique à tous les fichiers du répertoire courant :

$ each *.html sedx 's/XXX/YYY/'

Ou à tous les fichiers de la hiérarchie du répertoire :

$ reach *.html sedx 's/XXX/YYY/'

Ajoutez une gestion de paramètres au script :

$ cat sedx
#!/bin/sh

if [ "$2" = "" -o "$1" = "-usage" ]; then echo "Exécute une commande sed en écrivant dans le fichier d'origine." echo "Usage: ${0##*/} sed-command file" echo "Ou utilisez avec (r)each" echo "Usage: (r)each filetype ${0##*/} sed-command" exit fi
tmp=tmp-file-for-$PPID { sed "$1" "$2" > $tmp && mv $tmp "$2" } || rm $tmp

Scinder l'Ecran

Les astuces de cette semaine sont en rapport avec l'application Terminal d'Apple (/Applications/Utilities/Terminal.app).

Selectionner le mode scindé dans le Terminal en cliquant sur l'icône située dans le coin supérieur droit...

On peut alors faire défiler la partie supérieure pour voir les commandes précédentes tandis que l'on travaille dans la partie basse. Cela permet de faire des copier-coller entre les deux cadres.


Copier et Coller

Copier du texte dans la fenêtre du terminal en le sélectionnant comme vous le feriez dans d'autres applications (clic gauche et glisser). Le texte sélectionné est automatiquement placé dans un buffer qui peut être rappelé en cliquant sur le bouton du milieu de la souris *.

Pour coller du texte entre différentes fenêtres ou applications, utilisez la commande habituelle Commande-C (après avoir sélectionné le texte) pour copier, et Commande-V pour coller. Le Terminal supporte aussi le glisser-déposer sur di texte sélectionné.

Deux utilitaires à ligne de commande sont prodigués pour copier et coller :

$ pbpaste
Deux utilitaires à ligne de commande sont prodigués pour copier et coller :

(texte précédemment copié à partir d'une application dotée d'une interface utilisateur graphique)

$ echo "hello there" | pbcopy
$ pbpaste
hello there

* Une souris à trois boutons est pratique lorsque l'on travaille dans le Terminal d'Apple ou dans xterm.


Fichiers .command

Créez un script shell double-cliquable en l'enregistrant en tant que fichier '.command'. Tout script shell standard peut être sauvegardé dans un fichier avec l'extension '.command', et un double-clic entraînera l'ouverture d'un nouveau terminal et le lancement du script.

On peut aussi utiliser l'utilitaire 'open' pour lancer le script à partir de la ligne de commande (toujours dans une fenêtre de nouveau terminal).


Fichiers .term

Créez différents ensembles regroupant les réglages d'une fenêtre Terminal (couleurs, taille de fenêtre, ...). Enregistrez une session terminal en utilisant Fichier -> Enregistrer sous... pour créer un fichier '.term'. Un double-clic entraînera l'ouverture d'une fenêtre Terminal avec exactement les mêmes réglages que ceux de la fenêtre à partir de laquelle le fichier ".term" a été créé.

Placez le fichier dans le dossier ~/Library/Application Support/Terminal/ et il apparaîtra dans le menu Fichier du Terminal sous 'Fichier -> Bibliothèque -> ...'

Examinez un fichier '.term' et vous verrez :

ExecutionString

Ajoutez des commandes shell à cela :

ExecutionString
ls -al /; ls -al ~;ps -caux;df -h;exit

et vous obtiendrez un effet similaire à celui du fichier '.command' (voir Mercredi), mais avec en plus la possibilité de modifier les réglages de la fenêtre Terminal. Retirez ';exit' si vous souhaitez pas que la fenêtre se ferme avec exécution complète de Execution String.


Autres trucs

Déposer un dossier ou un fichier sur la fenêtre Terminal et le chemin d'accès complet sera inscrit sur la ligne de commande.

Le titre du Terminal peut être changé avec :

(bssh) declare -x PROMPT_COMMAND='echo -n -e "33]0;$USER@$HOSTNAME07"'
(tcsh) alias precmd 'printf "33]0;$user@$host07"'

Les exemples ci-dessus affiche le nom de l'utilisateur et celui de l'hôte en utilisant soit echo soit printf.


Information système

Cette semaine, je vais vous lister des commandes très utiles dont vous ne connaissez pas l'existence (ou que vous aviez peut-être oubliées). Reportez-vous au manuel Unix pour de plus amples détails.

Pour obtenir des informations sur le système :

$ arch
ppc

$ machine ppc7450
$ uname -v Darwin Kernel Version 7.3.0: Fri Mar 5 14:22:55 PST 2004; root:xnu/xnu-517.3.15.obj~4/RELEASE_PPC
$ hostinfo Mach kernel version: Darwin Kernel Version 7.3.0: Fri Mar 5 14:22:55 PST 2004; root:xnu/xnu-517.3.15.obj~4/RELEASE_PPC
Kernel configured for a single processor only. 1 processor is physically available. Processor type: ppc7450 (PowerPC 7450) Processor active: 0 Primary memory available: 768.00 megabytes. Default processor set: 94 tasks, 249 threads, 1 processors Load average: 2.37, Mach factor: 0.22
$ system_profiler (much output)

Manipuler des Fichiers (B)Zippés

Si vous souhaitez manipuler des fichiers zippés, utilisez la famille de commandes z*. Par exemple, utilisez 'zmore' pour voir un fichier au lieu de le dézipper, et ainsi en voir le contenu décompressé.

$ ls /usr/bin/z*

/usr/bin/zcat /usr/bin/zdiff /usr/bin/zgrep /usr/bin/zmore /usr/bin/zprint /usr/bin/zcmp /usr/bin/zforce /usr/bin/zip /usr/bin/znew

Si les fichiers sont compressés avec bzip2, utilisez la famille de commandes bz* :

$ ls /usr/bin/bz*
/usr/bin/bzcat   /usr/bin/bzegrep  /usr/bin/bzip2         /usr/bin/bzmore
/usr/bin/bzcmp   /usr/bin/bzfgrep  /usr/bin/bzip2recover
/usr/bin/bzdiff  /usr/bin/bzgrep   /usr/bin/bzless

Scripts Parlants

Utilisez directement (sans passer par osascript) la commande 'say' pour ajouter de la parole à vos scripts :

$ say "Hello world."

Recherchez des mots à prononcer avec 'look' :

$ look zy
zyga
zygadenine
Zygadenus
Zygaena
zygaenid
Zygaenidae
...

Ou scruttez le dictionnaire avec grep :

$ grep "^d...p$" /usr/share/dict/web2
dadap
decap
dreep
droop

Ou le dictionnaire en ligne pour la signification de 'fuci':

$ curl dict://dict.org/d:fuci
220 pan.alephnull.com dictd 1.8.0/rf on Linux 2.4.18-14  <1904283.29426.1084790981@pan.alephnull.com>
250 ok
150 1 definitions retrieved
151 "Fuci" web1913 "Webster's Revised Unabridged Dictionary (1913)"
Fucus Fu"cus, n.; pl. {Fuci}. [L. rock lichen, orchil, used as
   a red dye, red or purple color, disguise, deceit.]
      1. A paint; a dye; also, false show. [Obs.]

2. (Bot.) A genus of tough, leathery seaweeds, usually of a dull brownish green color; rockweed.
Note: Formerly most marine alg? were called fuci. . 250 ok [d/m/c = 1/0/22; 0.000r 0.000u 0.000s] 221 bye [d/m/c = 0/0/0; 0.000r 0.000u 0.000s]

Mise à jour de Logiciel

Effectuez une mise à jour de logiciel, éventuellement en ligne, avec l'outil à ligne de commande Software Update :

$ softwareupdate -l
Software Update Tool
Copyright 2002-2003 Apple Computer, Inc.
Your software is up to date. (Votre logiciel est à jour)

N'oubliez pas 'nvram' pour manipuler les paramètres de l'open firmware :

Pour lister les variables nvram :

$ nvram -p

Pour activer la connexion verbeuse (équivalent à Command-V au démarrage) :

$ sudo nvram boot args="-v"

Utilisez 'bless' pour changer le volume de démarrage :

sudo bless -folder '/Volumes/vol-name/System/Library/CoreServices' -setOF
sudo bless -folder '/System/Library/CoreServices' -setOF

Manipulation d'Image

Utilisez le Scriptable Image Processing System (commande sips) pour manipuler des images via la ligne de commande ou AppleScript.

Il n'y a pas de page de manuel (man), utilisez donc :

$ sips --help

Edition de la Ligne de Commande

Les astuces de cette semaine vous aideront à saisir des commandes Bash plus rapidement et plus facilement.

Tout d'abord, l'édition de la ligne de commande :
Editez la ligne courante (ou provenant de l'historique des commandes invoqué en pressant la touche 'flèche vers le haut') avec plus de possibilités que celles offertes par l'habituel curseur et la touche d'effacement (del).

control-A déplace le curseur en début de ligne
control-E déplace le curseur en fin de ligne

escape-del efface le mot derrière le curseur
del efface le caractère derrière le curseur
control-d efface le caractère après le curseur
esc-d efface le mot après le curseur

control-k efface tout jusqu'à la fin de la ligne
control-u efface toute la ligne

Ces commandes seront familières aux utilisateurs d'Emacs.

Pour utiliser le mode d'édition de 'vi', tapez la commande :

$ set -o vi

et pour revenir au mode 'Emacs' :

$ set -o emacs

Recherche dans l'Historique des Commandes

Trouvez rapidement une ligne de commande que vous avez tapée précédemment puis répétez la ou modifiez la. Tapez control-r puis commencez à taper la commande :

$ control-r
(reverse-i-search)`':
type si
(reverse-i-search)`si': vim signal.c
type t
(reverse-i-search)`sit': vim ~/sites/index.html

Commencez par taper une quelconque partie de la ligne de commande, par exemple la commande ou le nom du fichier, et bash recherchera dans son historique la première commande correspondant à ce que vous avez tapé n'importe où sur la ligne. Continuez de taper jusqu'à ce que la commande correcte soit montrée, ou pressez control-r encore pour remonter encore dans l'historique. Lorsque la commande souhaitée est affichée pressez retour pour l'exécuter ou pressez la flèche droite pour l'éditer.


Répéter

Répétez une suite de commandes :
Pressez la touche Haut jusqu'à ce que la première commande de la séquence à répéter soit affichée. Puis, au lieu de taper retour, tapez control-o. La commande sera exécutée puis la commande suivante sera affichée prête à être exécutée ou modifiée.

La séquence escape-. rappelle le nom de fichier de la commande précédente.

Tapez :

$ ls -al osxfaq

puis :

$ cd escape-.

sera changée en

$ cd osxfaq

- particulièrement utile pour des noms de fichiers longs ou compliqués.

En plus, la variable shell $_ peut être utilisée :

$ echo $_
osxfaq

Extension de la Ligne de Commande

Vous savez probablement que le fait de presser la touche Tabulation permet de compléter le nom d'un fichier. Vous pouvez aussi utiliser Tabulation pour compléter des commandes, des alias et des fonctions.

Si le mot commence par $, alors une pression sur la touche Tab complètera le mot en se basant sur les variables shell définies. De la même manière, ~ (tilde) sera complété en se basant sur les noms d'utilisateurs et @ en se basant sur des noms d'hôtes.

Pour que @ fonctionne, la variable HOSTFILE doit porter le nom d'un fichier contenant des entrées au même format que le fichier /etc/hosts. (Voir 'man hosts')


Eviter l'Historique

Vous pouvz faire en sorte qu'une des lignes particulières ne soient pas mémorisées dans l'historique, ceci est pratique si la commande contient des informations sensibles tels qu'un mot de passe.

Il y a deux techniques :

Positionner la variable d'environnement HISTCONTROL:

$ declare -x HISTCONTROL="ignoreboth"

Maintenant, les commandes commençant avec un espace ne seront pas mémorisées dans l'historique. De plus, les lignes correspondant à la dernière ligne de l'historique ne seront pas ajoutées.

Pour contrôler ces aspects individuellement, utilisez 'ignorespace' ou 'ignoredups' au lieu de 'ignoreboth'.

La seconde technique consiste à positionner la variable d'environnement HISTIGNORE à une liste de modèles séparés par des point-virgules. Pour plus de détails, se reporter à 'man bash' et rechercher le terme HISTIGNORE.


Obtenir la Meilleure Aide

Utilisez le système d'aide de Bash pour obtenir des informations sur les commandes pré-enregistrées. (Vous ne les verrez pas dans les pages 'man' d'Unix)

$ help

pour les llister toute.

$ help

pour afficher la page d'aide d'une commande donnée.

Fournissez un modèle et Bash affichera une page d'aide pour chaque commande correspondant au modèle ou un petit synopsis si l'option est -s est donnée.

$ help -s "re*"

Obtenir la Bonne Commande

Lorsque vous tapez une commande telle que 'ls', Bash peut être amené à exécuter un alias, une fonction, une commande interne ou une provenant du chemin d'accès ($PATH). Déterminez le type de commande que Bash exécutera en utilisant la commande 'type'. Elle est analogue à la commande 'which' du shell tcsh.

$ type ls
ls is aliased to `/usr/local/bin/ls --color=tty'

Visualisez toutes les possibilités avec :

$ type -a ls
ls is aliased to `/usr/local/bin/ls --color=tty'
ls is /usr/local/bin/ls
ls is /bin/ls

Forcer la Bonne Commande

L'astuce de Mardi vous a montré comment déterminer la variante d'une commande que Bash va exécuter. Et si vouliez maintenant surpasser cela ?

L'ordre de recherche de Bash est le suivant :
alias, mots clés, fonctions, commandes internes, commandes trouvées par le chemin d'accès $PATH

Utilisez la commande interne suivante de Bash pour changer l'ordre de recherche (changement applicable qu'à une seule commande) :

  • 'command' force la recherche uniquement sur les commandes internes ou celles trouvées par $PATH, ignorant les alias, les mots clés et les fonctions
  • 'builtin' force la recherche uniquement sur les commandes internes
  • 'enable' force la recherche seulement sur les commandes de $PATH

Par exemple :

$ command ls

force l'exécution de 'ls' à partir de $PATH, évitant ainsi les alias ou fonctions que vous auriez pu définir pour 'ls'.

Note : le shell 'tcsh' utilise un backslash ('\')

% ls

pour éviter les alias et les commandes internes.


Alias

Listez tous les alias avec :

$ alias

Créez un alias avec :

$ alias la="/bin/ls -Al"

Supprimez un alias avec :

$ unalias

Voici un truc pour faire des alias à partir de noms de répertoire. Normallement, Bash effectue une substitution d'alias seulement sur le premier mot d'une ligne de commande (la commande seulement) ...

$ pwd
/Users/saruman

$ alias pref="~/Library/Preferences/"
$ cd pref
-bash: cd: pref: No such file or directory

...ainsi cela ne marche pas.

Mais faites un alias de cd comme ci-dessous (notez le blanc à la fin)...

$ alias cd="cd "
$ cd pref
$ pwd
/Users/saruman/Library/Preferences

... et cela marche maintenant.


Fonctions

Sous Bash, à l'inverse du shell tcsh, les alias ne peuvent pas prendre de paramètres. Bash est caractérisé par la plus puissante construction de 'fonctions'.

Déclarez une function 'psx' :

$ psx () { ps axww | grep -i $* | grep -v grep;}

La variable spéciale $* est étendue à tous les paramètres passés à la fonction. Autrement, utilisez $1, $2, ... pour le premier et second (et ainsi de suite) paramètres. C'est exactement le même schéma que celui utilisé pour étendre les paramètres passés aux scripts shell.

$ psx safari
503 ?? S 12:36.51 /Applications/Safari.app/Contents/MacOS/Safari -psn_0_2359297

Voici une fonction pour voir les fichiers log :

$ tlog () { tail -f -n40 /var/log/$1.log;}

Et :

$ tlog system

verra le log système (contrôle-C pour sortir).

Pour lister toutes les fonctions :

$ declare -f

ou

$ declare -F

pour ne lister que les noms de fonction.


Faire des Sous-Shell ou ne pas Faire des Sous-Shell

Apprenez la différence entre lancer un shell et 'sourcer' un shell. Illustration :

$ declare -x NEW_ENV_VAR="XXXX"
$ new_var="xxxx"
$ echo $NEW_ENV_VAR
XXXX
$ echo $new_var
xxxx

$ cat tst
#!/bin/bash
declare -x NEW_ENV_VAR="TEST"
new_var="test"

Lancez le script :

$ ./tst
$ echo $NEW_ENV_VAR
XXXX
$ echo $new_var
xxxx

Remarquez que les variables n'ont pas changé...

'Sourcez' le script:

$ source tst
$ echo $NEW_ENV_VAR
TEST
$ echo $new_var
test

...et cette fois ci elles ont changé.

Le lancement d'un script comme dans le premier exemple lance un nouveau shell. Lorsque le nouveau shell se termine, ses variables d'environnement ne sont pas passées au shell parent, elles sont donc perdues et celles du shell original restent inchangées.

Le fait de faire un 'sourcing' d'un script l'exécute dans le shell courant. Les variables d'environnement/shell réglées par le script sont celles du shell courant et restent donc positionnées après que le script se soit terminé.

Remarquez que :

$ source ./tst

et

$ . ./tst

sont équivalents.


Parenthèses

Utilisez des parenthèses pour exécuter des commandes dans un sous-shell.

$ cat tst2
new_var="xxxx"
echo $new_var

(new_var="test")
echo $new_var

$ ./tst2
xxxx
xxxx

Vous devez vous attendre à ce que ce script vous renvoie

xxxx
test

Parce que la seconde assignation est entre parenthèses elle est exécutée dans un sous-shell et (rappelez vous de l'astuce de Lundi) elle n'a aucun effet sur l'environnement du shell parent.

Vous souhaiterez exécuter de nombreuses commandes dans un sous-shell lorsque leur sortie est redirigée ou envoyée à une autre commande (pipe).

En guise d'illustration :

$ echo hello; echo world > outfile
hello
$ cat outfile
world

$ (echo hello; echo world) > outfile
$ cat outfile
hello
world

Accolades

Utilisez les accolades pour exécuter un sous-shell.

L'astuce de Mardi a exécuté une liste de commandes placées entre parenthèses :

$ (echo hello; echo world) > outfile

Vous pouvez obtenir le même effet avec des accolades :

$ { echo hello; echo world;} > outfile

sauf que la liste de commandes est exécutée dans le shell courant, pas dans un sous-shell. (Comme la différence entre lancer ou sourcer comme expliqué dans l'astuce de Lundi)

Notez l'espace après l'accolade ouvrante et le point-virgule avant l'accolade fermante. Ces contraintes de syntaxe sont plus strictes pour les accolades que pour les parenthèses.


eval

Utilisez 'eval' pour supasser l'ordre d'analyse des commandes du shell.

Eval est une commande subtile et utile. Considérez ce script qui lance des commandes en arrière-plan.

$ cat tst
#!/bin/bash
"$*" > ~/outfile &

$ tst 'du -sk *'
./tst: line 2: du -sk *: command not found
$ tst 'ls | grep "^D"'
./tst: line 2: ls | grep "^D": command not found

Le script échoue parce que le shell considère que le premier mot ("$*") est une commande *puis* développe $*. Nous devons changer l'ordre d'évaluation du shell. Le fait d'enlever les apostrophes autour de "$*" ne marchera pas non plus :

$ cat tst
#!/bin/bash
$* > ~/outfile &

Voilà la solution :

$ tst 'du -sk *'
$ cat ~/outfile
5524 Desktop
1992 Development
...

Mais la seconde commande échoue toujours. Encore une fois, le shell gère les symboles avant de les développer et n'arrive pas à reconnaître que le '|' est un symbole, le symbole du pipe.

$ tst 'ls | grep "^D"'
$ ls: |: No such file or directory
ls: grep: No such file or directory
ls: "^D": No such file or directory

Maintenant, essayez avec 'eval' :

$ cat tst
#!/bin/bash
eval "$*" > ~/outfile &

$ tst 'du -sk *'
$ cat ~/outfile
5524 Desktop
1992 Development
...

$ tst 'ls | grep "^D"'
$ cat ~/outfile
Desktop
Development
Documents

Ça marche. Pourquoi ? Le shell développe "$*" comme d'habitude. Ce que eval fait consiste à évaluer la ligne de commande, donnant au shell une seconde chance de considérer que '|' est le symbole du pipe.


nohup

Commencez une liste de commandes sous-shell, ou un script, en utilisant 'nohup' si vous souhaitez qu'il reste actif après que le shell ait fini de lancer les commandes.

Normalement, le shell envoie un signal HUP à tous ses sous-process lorsqu'il reçoit lui aussi un HUP ou une commande 'exit'. 'Nohup' empêche cela.

Autrement, construisez un gestionnaire de signaux dans le script pour capturer le signal HUP et l'ignorer.

Note :
En fonction de ses réglages, bash peut envoyer ou ne pas envoyer de signal HUP à ses sous-process.

Vérifiez le avec :

$ shopt huponexit
huponexit off

(HUP est désactivé en sortie)

Activez le avec :

$ shopt -s huponexit
$ shopt huponexit
huponexit on

Pour désactiver de nouveau :

$ shopt -u huponexit
$ shopt huponexit
huponexit off

'Huponexit' s'applique à tous les sous-process, alors que la commande 'nohup' est appliquée sur un process donné.


Changez Votre Shell

Utilisez NetInfo pour changer votre shell par défaut. Si votre utilisateur a été créé avant Panther, vous devez peut-être encore utiliser tcsh au lieu de bash.

La manière graphique :

Lancez le Gestionnaire NetInfo dans /Applications/Utilities et allez à :

| / | users | your-user-name |

dans les panneaux du haut. Cliquez sur votre nom d'utilisateur. Ensuite, dans le panneau du bas, faites défiler jusqu'en bas jusqu'à ce que vous voyez 'shell' dans le panneau 'Property'. Changez la valeur dans le panneau 'Value(s)' en '/bin/bash'.

Vous devrez vous authentifier d'abord en cliquant sur le cadenas placé en bas à gauche et en saisissant votre mot de passe administrateur.

La manière ligne de commande :

Utilisez la ligne de commande des services de répertoire (remplacez 'saruman' par votre propre nom court d'utilisateur).

$ sudo dscl . -create /users/saruman shell /bin/bash

Restaurer le Status Admin

Restaurer le Statut de l'utilisateur Admin.

Si votre utilisateur admin a perdu son statut d'administrateur pour une quelconque raison (et c'est arrivé à pas mal de gens) et que vous n'avez pas de deuxième utilisateur adminsitrateur, vous devez démarrer en mode utilisateur unique et utilisez 'nicl' pour vous ajouter de nouveau au groupe administrateur.

Maintenez pressées les touches commande et 's' au démarrage et attendez que le texte s'arrête de défiler. Tapez la commande :

$ mount -uw /

pour monter le disque système avec des autorisations en écriture (il sera déjà monté mais en lecture seule).

Restaurer le statut de l'administrateur en utilisant 'nicl'. Vous ne pouvez utililser aucun autre utilitaire tel que 'niload' car le démon nécessaire des services système ne tourne pas.

$ nicl -raw /var/db/netinfo/local.nidb -merge /groups/admin users votre-nom-d-utilisateur-ici

(Tout sur une même ligne.)


Les Utilitaires 'ni'

Gérez la base de données NetInfo.

Questionner la base de données Netinfo pour voir quels utilisateurs utilisent le shell 'sh' oo 'bash'.

Avec nigrep :

$ nigrep "/bin/b?a?sh" .
12 /users/root: shell /bin/sh
67 /users/saruman: shell /bin/bash

nigrep prend comme argument une expression régulière comme grep et cherche dans la base de données.

Avec nireport :

$ nireport . /users name shell
nobody /usr/bin/false
root /bin/sh
daemon /usr/bin/false
...
saruman /bin/bash

nireport prend comme argument un répertoire (/users dans cet exemple) et une liste de propriétés à afficher.

Listez les répertoires NetInfo avec nidump. nidump affiche les répertoires NetInfo au format Unix standard :

$ nidump group .
nobody:*:-2:
nogroup:*:-1:
wheel:*:0:root
...
saruman:*:501:

Chargez des données dans NetInfo avec niload. niload chargera la base à partir de fichiers plats standard Unix :

$ sudo niload -dm group . < flat-file

Consultez 'man niload' pour voir si vous avez besoin des options 'd'elete ou 'm'erge.

Gérez la base de données avec niutil or nicl. Je préfère utiliserto 'dscl' pour cela, et j'en parlerai dans les astuces de la semaine prochaine.


Backup et Restore

La base de données NetInfo est sauvegardée quotidiennement avec :

/private/var/backups/local.nidump

Vous pouvez faire cela vous-même avec :

$ nidump -r / -t localhost/local > local.nidump

Restaurez une base de données corrompues avec :

Démarrez en mode mono-utilisateur (maintenez Commande-s au démarrage et attendez que le texte finisse de défiler). Tapez les commandes :

$ mount -uw /
$ mv /var/db/netinfo/local.nidb /var/db/netinfo/corrupt.nidb

Les prochaines étapes ont été tirées d'un article publié chez O'Reilly. Elles lancent NetInfo et créent une base de données vide.

$ /usr/libexec/kextd
$ /usr/sbin/configd
$ /sbin/SystemStarter
$ /usr/libexec/create_nidb
$ /usr/sbin/netinfod -s local

Enfin, utilisez niload pour charger la base de données sauvegardées :

$ niload -d -r / . < /path/to/backed-up/database

Changer l'Ordre de Recherche

Sous Panther, la plupart des fichiers Unix sont scrutés, comme NetInfo et les Services de Répertoire.

Vérifiez l'ordre de recherche des services avec :

$ lookupd -configuration

Changez cela pour tout service en créant un fichier dans le répertoire '/etc/lookupd/'. Par exemple, pour contrôler comment sont recherchés les mounts NFS (par défaut NetInfo mais pas le /etc/fstab 'fichier plat') créez un fichier appelé mounts:

$ cat /etc/lookupd/mounts
LookupOrder Cache FF NI DS

Cela indique de scruter les fichiers plats, puis NetInfo et enfin les Directory Services.


Les Signaux

Les astuces de cette semaine abordent les signaux Unix et la manière de les gérer dans des scripts shell Bash. Aujourd'hui, je vous parlerai des signaux et des interruptions.

Envoyez un signal à un process actif en utilisant 'ps' et 'kill' avec une simple fonction bash.

Fonction :

$ killsig () { kill -$1 $(ps x | grep $2 | grep -v grep | awk '{print $1}'); }

Usage :

$ killsig TERM processname

Listez quelques uns des signaux les plus communs :

$ man kill

Rappelez vous que certains signaux sont associés à des touches :

INT - contrôle-c
SUSP - contrôle-z
QUIT - contrôle-q

Listez les associations avec stty :

$ stty -e

Changez les associations (associez une interruption à control-x au lieu de contrôle-c) :

$ stty intr ^x

Capturer les Signaux

Un signal est une interruption envoyée à un process Unix actif. Normalement, le signal provoque la fin du process (script ou exécutable). Cependant, un process peut capturer le signal et effectuer une autre action.

Capturez les signaux dans des scripts bash :

$ cat trap1
#!/bin/bash

trap 'echo "On no you dont"' INT trap 'echo "not that way either"' TERM
while true; do echo "Hello........" # utiliser sleep pour représenter un long bloc de code sleep 1 done

Si le script reçoit un signal INT ou TERM via 'kill', ou un signal INT via contrôle-c, il exécutera la commande donnée par la trappes appropriée puis il continuera là où il s'est arrêté. Dans cet exemple, il affichera un message à l'écran.

Lancez trap1 :

$ ./trap1
Hello........
^XOn no you dont
Hello........
not that way either
Hello........
Hello........

Dans une autre fenêtre (en utilisant la fonction killsig de Lundi) :

$ killsig INT trap1
$ killsig TERM trap1
$ killsig KILL trap1

Syntaxe :

trap "commande à exécuter" SIGNAL-LIST

Functions Trappe

Utilisez une fonction si vous avez besoin d'un gestionnaire de trappes plus sophistiqué :

$ cat trap2
#!/bin/bash

handlehup () { echo "J'ai eu un HUP" echo "Je vais maintenant recharger ma configuration" #...... }
trap "handlehup" HUP
while true; do echo "Hello........" # utiliser sleep pour représenter un long bloc de code sleep 1 done

Si un signal HUP est envoyé à ce script, il sera attrapé par 'trap' et la fonction 'handlehup' sera exécutée. Lorsque la fonction sera terminée, le script continuera son exécution au point où il s'était arrêté.

$ ./trap2
Hello........
J'ai eu un HUP
Je vais maintenant recharger ma config
Hello........
^C
$

Dans une autre fenêtre (en utilisant la fonction de l'astuce de Lundi) :

$ killsig HUP trap2

Le signal HUP signal (hangup) est généralement utilisé pour indiquer au process de recharger configuration et de redémarrer. Apache répondar à un signal HUP de cette manière (bien que l'on utilise 'apachectl' en général).


Poser une Trappe sur une Section de Code

Limitez vos fonctions trappes qu'à la partie critique d'un script, souvent autour d'un nombre de commandes ne devant pas être interrompues.

Ce script attrape les signaux HUP, INT et TERM autour du code critique puis pousse le gestionnaire vers le code normal.

$ cat trap3
#!/bin/bash

handlesig () { echo "Got an INT" #...... }
# critical code - stop interrupts trap "handlesig" HUP INT TERM
echo "Critical code"
# use sleep to represent a lengthy block of code sleep 1; sleep 1; sleep 1; sleep 1; sleep 1; sleep 1 sleep 1; sleep 1; sleep 1; sleep 1; sleep 1; sleep 1
# normal code - allow interrupts trap - HUP INT TERM
echo "Normal code" sleep 1000

L'instruction :

trap - SIGNAL-LIST

retire un gestionnaire des signaux listés et le remplace par celui par défaut (s'il y en a un).

$ ./trap3
Critical code
Got an INT
^CGot an INT
Normal code
Hangup

Dans une autre fenêtre (en utilisant la fonction killsig de Lundi) :

$ killsig HUP trap3
(wait a bit until normal code is entered)
$ killsig HUP trap3

Poser une Trappe sur une Section avec des Sous-Shells

Limitez vos fonctions trappes à seulement la partie critique d'un script, comme Jeudi, mais en utilisant des sous-shells. Un gestionnaire assigné à un sous-shell n'hérite pas du shell parent.

Ce script attrape les signaux INT (control-c) autour du code critique.

$ cat trap4
#!/bin/bash

# critical code - stop interrupts ( trap 'echo "Caught by subshell"' INT
echo "Critical code" sleep 1; sleep 1; sleep 1; sleep 1; sleep 1; sleep 1 sleep 1; sleep 1; sleep 1; sleep 1; sleep 1; sleep 1 )
# normal code - allow interrupts echo "Normal code" sleep 1000
$ ./trap4 Critical code ^CCaught by subshell ^CCaught by subshell ^CCaught by subshell Normal code ^C $

Listez tous les signaux avec :

$ trap -l

Et obtenez en plus sur la commande 'trap' intégrée au bash avec :

$ help trap

Tâches en Arrière Plan

Servez vous des Tâches en Arrière Plan pour les traitements qui durent très longtemps et qui ne nécessitent aucune entrée/sortie via le Terminal, ou qui lancent leur propre fenêtre (xterm par exemple).

Ces astuces s'appliquent au shell bash mais tcsh supporte aussi les Tâches en Arrière Plan.

Lancez une nouvelle fenêtre xterm avec :

$ xterm &
[1] 707

et une fois que xterm sera lancé vous aurez de nouveau le contrôle du terminal original. Le symbole '&' indique à bash de lancer la commande en arrière plan.

[1] est le numéro de la tâche
707 est le PID, comme indiqué par 'ps'

$ ps x | grep "[x]term" 707 std S 0:00.16 xterm

Utilisez :

$ jobs -l
[1]+ 707 Running xterm &

pour afficher une liste des tâches ainsi que leur numéro de process et leur PID.

Notez que chaque instance de bash (chaque fenêtre terminal) lance et contrôle sa propre liste de tâches. Le fait de taper 'jobs -l' sur un autre terminal ne montrera pas la tâche qui porte le PID 707.


Tâches Nécessitant des E/S

En général, les scripts qui requièrent des entrées/sorties ne sont pas lancés en arrière-plan. La sortie serait mélangée à celle de la tâche de premier plan et les entrées ne marcheraient pas.

Utilisez une redirection de fichier si une tâche en arrière-plan affiche des données ou requiert des entrées prévisibles :

$ cat script
#!/bin/bash
read -p "Name: " name
echo Vous déclarez être $name.
...

$ cat in
Adrian

$ ./script out &
[7] 809
$

Quand la tâche se termine le terminal affiche :

[7]   Done                    ./script &out

Et pour prouver qu'il a marché :

$ cat out
Vous déclarez être Adrian.

Mettre en Arrière-plan une Tâche Active

Reprennez la main via le terminal sur une tâche que vous avez placée en arrière-plan. Pressez contrôle-z pour suspendre la tâche, puis tapez 'bg' pour la place en arrière-plan. La tâche va alors continer de s'exécuter comme si vous l'aviez lancée en arrière-plan en utilisant '&'.

$ xterm (oops! I forgot the &)
^Z
[7]+ Stopped xterm

$ bg
[7]+ xterm &

$ (contrôle retourné au terminal courant)

Basculer les Tâches

Utilisez 'fg' et 'bg' pour gérer les tâches en arrière-plan.

$ fg %n

place la tâche numéro n en premier-plan. 'fg' sans paramètre opère sur la tâche la plus récemment mise en arrière-plan. Vous pouvez aussi spécifier le numéro PID avec 'fg' en omettant le %.

Fournissez une entrée à une tâche placée en arrière-plan (cette exemple utilise le script de Mardi) :

$ ./script & 
[2] 905
Name: $ 

[2]+ Stopped ./script

Ici, le Terminal indique que la tâche 2 a été stoppée. Utilisez 'jobs -l' pour en connaître la cause...

$ jobs -l
[1]-   893 Running                 xterm &
[2]+   905 Stopped (tty input)     ./script

...elle nécessite une entrée à partir du terminal '(tty input').

Placez la tâche en premier-plan :

$ fg %2
./script

Fournissez maintenant l'entrée :

Adrian
Vous déclarez être Adrian.

$ bg

enverra la tâche de nouveau en arrière-plan si elle a besoin de continuer son exécution. 'bg' peut prendre comme argument %numéro-de-tâche ou le PID comme pour 'fg'. Sans paramètre, elle se base sur la tâche dernièrement placée en premier-plan.


Attendre...

Si un shell (ou un script) s'arrête alors que des tâches en arrière-plan qu'il contrôle sont toujours actives, ces tâches deviennet orphelines. Elles ne peuvent être arrêtées qu'avec :

$ kill -KILL

Eviter qu'un script crée des tâches orphelines en utilisant 'wait'.

$ wait

évitera que le shell (et donc le script) s'arrête tant que les tâches qu'il a sous contrôle ne sont pas terminées.

$ wait %n

attend seulement la tâche numéro n. Vous pouvez spécifier aussi un PID sans le '%'.


[ vs Test

Utilisez :

$ man test

ou :

$ man [

pour savoir quelles conditions on peut utiliser sous les scripts des shells Bash et Bourne pour les instructions 'if', 'while' et 'until'.

Les conditions sous Bash sont évaluées par la commande 'test', qui peut tester des fichiers, des chaînes et des nombres. La commande est aussi appelée '[' qui explique la forme d'une condition Bash.

$ if [ 3 -lt 7 ]; then
    echo "3 est plus petit que 7" 
  else
    echo 'très bizarre !'
  fi
3 est plus petit que 7

Une forme équivalente :

$ if test 3 -lt 7; then ...

Pourquoi ";" doit être placé avant 'then' ?


Conditions et Instructions

Utilisez plus les conditions Bash - comprenez qu'une condition est réellement une commande. Bash exécutera la 'condition' et testera la valeur retournée.

0 (success) = true
not 0 (failure) = false

Ceci est en rapport avec les explications de Lundi concernant les commandes 'test' et '['.

Par exemple :

$ if diff f1.txt f2.txt; then
    echo "Les fichiers sont identiques"
  else
    echo "Les fichiers sont différents"
  fi
Les fichiers sont identiques

La valeur de retour d'une commande est tenue dans une variable shell $?

$ diff f1.txt f2.txt
$ echo $?
0

AND et AND et OR ou OR

Utilisez les constructions AND et OR pour bâtir des conditions plus complexes.

$ a=1;b=2;c=3
$ if [ $a -lt $b -a $b -lt $c ]; then
    echo "a < b < c"    
  else
    echo "et non"
  fi
a < b < c

L'instruction de test utilise les opérateurs -a pour AND et -o pour OR.

Autrement, utilisez les opérateurs AND et OR de Bash :

$ if [ $a -lt $b ] && [ $b -lt $c ]; then
    echo "a < b < c" 
  else
    echo "et non"
  fi
a < b < c 

La différence entre les deux :

Dans le premier exemple, la commande 'test' '[ ... ]' évalue l'expression entière.

Dans le second exemple, 'test' est appelée deux fois et Bash évalue 'premier résultat de test' AND 'second résultat de test'.


Conditions Bash Intégrées

Utilisez les tests intégrés de Bash pour l'arithmétique des entiers (et seulement les entiers). L'utilisation de '<' au lieu de '-lt' rendent les tests plus lisibles. L'expression est entourée par (( ... )) au lieu de [ ... ].

$ if (( ($a < $b) && ($b < $c) )); then
    echo "a < b < c"
  fi
a < b < c

ou :

$ if (($a < $b)) && (($b < $c)); then
    echo "a < b < c"
  fi
a < b < c

Comprenez la différence entre les deux formes.


Tests Plus Complexes

Comprenez comment formuler des expressions complexes. Quelques fois, les expressions doivent être placées entre crochets pour forcer l'ordre correct de l'évaluation. (Bien que dans l'exemple qui suit les crochets ne sont pas strictement nécessaires)

$ a=3;b=2;c=1

$ if [ ( $a -lt $b ) -a ( $b -lt $c ) ]; then echo "a < b < c " else echo "not so " fi -bash: syntax error near unexpected token `$a'

Erreur de syntaxe, nous devons échapper l'expression entre crochets.

Essayez :

$ if [  '( $a -lt $b )  -a  ( $b -lt $c )'  ]; then
    echo "a < b < c "
  else
    echo "not so "
  fi
a < b < c 

3 < 2 < 1 ! You jest.

Essayez maintenant :

$ if [  ( $a -lt $b )  -a  ( $b -lt $c )  ]; then
    echo "a < b < c "
  else
    echo "not so "
  fi
not so 

C'est nettement mieux.

Essayez de voir pourquoi nous avons obtenu une erreur dans la seconde forme.


Caractères Bash Spéciaux

Connaître les caractères spéciaux.

Bash traite de manière spéciale de nombreux caractères. Si l'un de ces caractères apparaît nu (sans guillemet ou sans caractère d'échappement) sur la ligne de commande, il est remplacé ou interprété.

Voici un rappel pratique.

#        démarre un commentaire
;        séparateur de commande
{...}    signifie un bloc de commande
(...)    force l'exécution dans un sous-shell
&&       ET logique (placé entre des commandes)
||       OU logique (placé entre des commandes)

~ remplacé par le répertoire de départ de l'utilisateur en cours ~user remplacé par le répertoire de départ de l'utilisateur user / séparateur de répertoire/fichier
$var remplacé par la variable 'var' `...` execute une commande et substitue la sortie $(...) syntaxe préférée de Bash pour la substitution de commande $((...)) évalue une expression arithmétique entière ((...)) évalue une expression arithmétique entière dans une condition
' guillemet " apostrophe \ échappe le caractère suivant (annule une signification spéciale)
* joker [...] ensemble de caractères joker ? caractère joker unique
& force l'exécution en arrière-plan de la commande < redirrige l'entrée (stdin) > redirige la sortie (stdout) | pipe ! NOT logique de pipeline

D'autres...?


Citer et Echapper

Empêcher Bash d'interpréter des caractères spéciaux (voir Lundi).

Il y a trois méthodes:

1) Echappement avec Backslash

$ a=5;b=4;c=3
$ echo \$1 \* \$b > \$c
$1 * $b > $c

Aucun des $, * ou > n'a été interprété de manière spéciale.

2) Guillemets (citation forte)

$ echo '$a * $b > $c'
$a * $b > $c

Tout ce qui est dans '...' est traité de manière litérale : le shell n'interprète aucun caractère spécial.

3) Apostrophes (citation légère)

$ echo "$a * $b > $c"
5 * 4 > 3

Tout sauf $ et ce qui est dans "..." est traité de manière litérale : cela vous permet d'échapper des caractères spéciaux tout en développant des variables.

Si vous souhaitez mixer des litéraux $ et des développements de variables $, utilisez le backslash pour échapper le $ :

$ echo "\$1 * $b > \$$c"
$1 * 4 > $3

Astuce d'Utilisation des Guillemets

1) Paramètres

Il est parfois nécessaire d'utiliser des guillemets autour de paramètres comme dans l'exemple Awk suivant :

$ echo "Adrian's" | awk '{print "You cant have " $1 " $1"}'
You cant have Adrian's $1

Si j'avais voulu afficher "can't" au lieu de "cant", une première tentative aurait pu être :

$ echo "Adrian's" | awk '{print "You can\'t have " $1 " $1"}'
> (hit control-c)

Il n'est pas possible d'échapper le ' dans can't car il est placé à l'intérieur d'une chaîne '...'.

Utilisez :

$ echo "Adrian's" | awk '{print "You can'\''t have " $1 " $1"}'
You can't have Adrian's $1

Cela coupe le paramètre Awk en 3 chaînes adjacentes :

'{print "You can'
\'
't have " $1 " $1"}'

2) Rappelez vous que les guillemets n'ont rien de spécial quand elles sont à l'intérieur d'apostrophes, vous pouvez donc utiliser aussi :

$ echo "You can't have my \$"
You can't have my $

ou même :

$ echo "You can't have my $"
You can't have my $

car $ sans rien derrière est considéré comme le litéral $.


Evaluation du Shell

Comprenez l'ordre d'évaluation adopté par le shell.

Cela ne marche pas :

$ file="~/Desktop/"

$ ls $file
/usr/local/bin/ls: ~/Desktop/: No such file or directory

$ ls ~/Desktop/
A File

Le tilde (~) est un caractère spécial du shell et n'a aucun sens dans le système de fichier. Le fait de le placer entre guillemets évite que le shell ne le développe. Vous devez penser qu'il est développé dans l'expression :

ls $file

mais cela n'est pas le cas. Le shell développe '~' avant qu'il ne développe $variables, et il ne voit donc jamais le '~'.

Contournez le problème :

1) Utilisez eval

$ eval ls $file
A File

eval donne au shell une seconde chance pour développer. Le premier passage développe $file, puis le tilde est développé par 'eval'.

2) Ne mettez pas de guillemets

$ file=~/Desktop
$ echo $file
/Users/saruman/Desktop

$ ls $file
A File

La première ligne n'a pas de guillemet, file contient donc le chemin d'accès complet au lieu de '~/Desktop'

Si vous devez mettre des guillemets dans l'assignation de la variable file, utilisez $HOME.

$ file="$HOME/Desktop"

$ ls $file
A File

$HOME est développée dans l'assignation alors que ~ ne l'est pas.


Guillemets sur Plusieurs Niveaux

Comptez le nombre de fois que le shell évalue une expression.

Voici un exemple simple qui illustre le principe.

$ ls A\ Dir
A File

$ echo ls A\ Dir > script

$ ./script
ls: A: No such file or directory
ls: Dir: No such file or directory

Le script ne marche pas parce que le shell a traité l'espace échappé par le backslash au moment d'exécuter l'echo. Le fichier ne contient donc pas la séquence d'échappement :

$ cat script
ls A Dir

On doit échapper à la séquence d'échappement en écrivant escape-space dans le fichier. Les deux doivent être échappés par eux mêmes - nous devons écrire escape-escape escape-space :

$ echo ls A\\\ Dir > script
$ ./script
A File

Monter des Partages AFP

Monter un partage AFP en utilisant le Terminal.

Un partage AFP peut être monté n'importe où sur le système de fichiers?par exemple dans /Volumes ou à la racine de votre répertoire Départ. Le 'point de montage' doit être un répertoire existant.

Par exemple, pour monter mon répertoire départ à partir d'une autre machine (melkor) sur le point de montage 'melkor' situé dans mon répertoire départ de cette machine, j'utilise :

$ cd ~
$ mkdir melkor
$ mount -t afp afp://myuser:mypassword@melkor.mayo-family.com/myuser melkor
mount_afp: the mount flags are 0000 the altflags are 0020

'@melkor.mayo-family.com/myuser' est le nom d'hôte ou l'adresse IP du serveur suivi par le point de partage AFP comme ce que l'on voit dans le dialogue 'Se connecter à...' du Finder.

$ ls
Desktop      Documents  Movies  Pictures  Sites  melkor
Development  Library    Music   Public    bin    osxfaq

Pour démonter, utilisez :

$ umount melkor

et le répertoire sera supprimé.


Script de Montage AFP

Ces script est utile si vous avez des comptes sur plusieurs machines (de bureau ou portables). Il monte votre répertoire Départ d'une autre machine.

L'utilisation la plus simple est :

$ mount-user
$ mount-user -usage
monte le répertoire Départ de youruser à partir du serveur yourserver

Utilisation : mount-user [-p password] [-h host] [-u user] [-p password] - utilise un mot de passe AFP si requis [-h host] - remplace yourserver comme serveur à monter [-u user] - remplace youruser comme utilisateur à monter

Il suppose ce qui suit.

Votre nom d'utilisateur est le même sur les deux machines, si ce n'est pas le cas remplacez le avec l'option '-u autrenom'.

Le nom du serveur est défini dans la variable d'environnement $ALM_SERVER, sinon remplacez le avec l'option '-h hostname/ip-address'.

Le point de montage sera $ALM_AFP_MOUNT/hostname/username, où $ALM_AFP_MOUNT est une variable d'environnement. Le chemin d'accès dans $ALM_AFP_MOUNT doit exister. /Volumes est le chemin d'accès usuel, mais vous pouvez le changer pour éviter des confusions avec les partages montés par le Finder (en /nfs par ex).

Le script créera tous les répertoires si nécessaire.

#!/bin/bash

# monte le répertoire Départ de l'utilisateur courant sur le serveur # $ALM_SERVER into the mount $ALM_AFP_MOUNT/... #
# fonction: usage ([error-message]) # affiche les lignes d'utilisation et quitte # prend un message d'erreur d'options à afficher à la fin # de la ligne usage usage () { echo "mount ${USER}'s home directory from server $ALM_SERVER" echo "" echo "Usage: ${0##*/} [-p password] [-h host] [-u user]" echo " [-p password] - use an AFP password if required" echo " [-h host] - override $ALM_SERVER as server to mount" echo " [-u user] - override $USER as username to mount" echo "" if [ "$*" != "" ]; then echo "Error: $*."; fi exit }

# function: exit_if_set (current-value, parameter-description) # appelée pour empêcher qu'un paramètre ait deux fois une valeur exit_if_set () { if [ "$1" != "" ]; then usage "$2 a déjà la valeur $1" else return fi }
# traite chaque paramètre dans une boucle et déplace chaque itération # de $2 -> $1 # opt="" while [ "$1" != "" ] do if [ "${1:0:1}" = "-" ]; then # found a - option introducer case "$1" in # ces options nécessitent une valeur, garde en mémoire l'option pour la prochaine itération # erreur si l'itération précédente était aussi une option nécessitant une valeur "-usage") usage;; "-p" | "-h" | "-u") if [ "$opt" = "" ]; then opt="$1" else usage "aucune valeur donnée pour $opt" fi ;;
# option invalide *) usage "invalid option $1";; esac else case "$opt" in # l'itération précédente était une option nécessitant une valeur, positionne la valeur "-p") exit_if_set "$password" "password"; password="$1";; "-h") exit_if_set "$host" "host"; host="$1";; "-u") exit_if_set "$user" "user"; user="$1";; "") usage "invalid value $1";; esac # une valeur a été trouvée pour -, on réinitialise ce drapeau opt="" fi shift done # cas où la dernière option était -, # alors aucune valeur n'a été donnée if [ "$opt" != "" ]; then usage "aucune valeur donnée à $opt" fi # valeurs par défaut pour les paramètres optionnels if [ "$host" = "" ]; then host="$ALM_SERVER"; fi if [ "$user" = "" ]; then user="$USER"; fi # traitement principal #
# si le mot de passe est donné, ajoute ":" au début pour se conformer # à la syntaxe de montage if [ "$password" != "" ]; then password=":"$password fi # vérifie si déjà monté mounted=$(df | grep "$ALM_AFP_MOUNT/$host/$user") # s'il n'est pas monté, on s'assure que le point de montage (répertoire) est dispo # supprime juste au cas où il existerait en tant que fichier, et cache # les erreurs if [ ! "$mounted" ]; then if [ ! -d $ALM_AFP_MOUNT/$host/$user ]; then rm -f $ALM_AFP_MOUNT/$host/$user 2> /dev/null rm -f $ALM_AFP_MOUNT/$host 2> /dev/null mkdir -p $ALM_AFP_MOUNT/$host/$user fi echo "Mounting afp://$user$password@$host/$user on $ALM_AFP_MOUNT/$host/$user." mount_afp afp://$user$password@$host/$user $ALM_AFP_MOUNT/$host/$user > /dev/null if [ "$?" != "0" ]; then echo "Erreur : le montage a échoué." exit 255 fi disktool -r fi # renvoie 0 si aucun montage n'a été effectué, 1 sinon if [ ! "$mounted" ]; then exit 1 else exit 0 fi

Activer NFS

La façon la plus simple d'activer NFS sur OS X est d'utiliser NFS Manager. Ce produit est brièvement décrit dans les astuces OSX (en anglais).

NFS Manager écrit les Partages et les Connexions (Montages) dans NetInfo. L'astuce vous montre comment autoriser NFS à fonctionner à partir des fichiers plats Unix traditionnels.

/etc/fstab définit quels partages à monter automatiquement (nécessaire sur la machine client)

/etc/exports définit quels répertoires à partager (nécessaire sur le serveur)

D'abord, forcez le démon automount à lire les fichiers plats. Par défaut, il utilisera NetInfo (Panther et Jaguar).

Créez le répertoire /etc/lookupd et le fichier mounts comme suit.

$ ls -al /etc/lookupd/
total 4
drwxr-xr-x    3 root     wheel         102 Apr 18 19:23 .
drwxr-xr-x  114 root     wheel        3876 Aug 15 22:39 ..
-rw-r--r--    1 root     wheel          28 Aug 19 13:19 mounts
$ cat /etc/lookupd/mounts
LookupOrder Cache FF NI

Sur Jaguar (mais pas Panther) il est nécessaire de forcer le démon RPC à démarrer en s'assurant que RPCSERVER est positionné sur -YES- dans /etc/hostconfig:

$ grep RPC /etc/hostconfig
RPCSERVER=-YES-

Ensuite, redémarrez la machine et réglez les partages (serveur) et les montages (client) ... astuce de Jeudi.


Réglage des Partages et Montages NFS

Pour définir des points de partage sur le serveur, éditez /etc/exports.

$ cat /etc/exports
/Users -alldirs -maproot=nobody -network=192.168.0.0 -mask=255.255.255.0
/Users/Shared -ro -mapall=nobody

Dans cet exemple, le répertoire /Users est exporté.

'-alldirs' permet à tout sous-répertoire de /Users d'être monté par un client

'-maproot=nobody' s'assure que l'utilisateur root sur le client n'a pas des accès root sur le serveur ; ESSENTIEL, à moins que vous sachiez exactement ce que vous faites

'-network...' et '-mask...' définissent la tranche d'IP autorisées à monter le partage. Il est ESSENTIEL que cette tranche ne comprenne que des machines de confiance (voir note plus bas).

J'ai exporté /Users/Shared en tant que lecture seule (-ro). Ceci est accessible à TOUTES les machines (aucune restriction IP). Il est exporté en Lecture Seule et tous les utilisateurs sont aiguillés vers l'utilisateur sans privilège 'nobody'.

Voir 'man exports' pour plus de détails.

Pour définir des points de montage sur le client :

$ cat /etc/fstab
# local mounts
#
...

# NFS mounts
#
carcharoth:/Users /nfs/Carcharoth nfs -b,-i,-P 0 0

Cette ligne recherche le partage /Users sur l'hôte carcharoth (vous pouvez utiliser soit le nom d'hôte, soit l'adresse IP) et monte le répertoire /nfs/Carcharoth. '/nfs' doit exister mais le point de montage réel 'Carcharoth' sera créé automatiquement.

'nfs' indique que le partage est nfs

Les options -b,-i -P sont décrites dans 'man mount_nfs'.

Les deux derniers ( 0 0 ) indique la 'dump frequency' et l'ordre de vérification du système de fichier. Ils ne sont pas utilisés.

Note :

NFS n'utilise aucun mot de passe pour l'authentificationn mais plutôt les ID Unix du User et du Group. Il est supposé qu'ils soient cohérents sur le serveur et sur tous les clients. En fait, un compte utilisateur sur la machine client aura les mêmes ID de user et de group que ceux de son compte sur le serveur (et tous les autres clients). Ceci est vrai en général sur un réseau client-serveur propre où les données utilisateurs sont gérées sur le serveur.

Si une machine client se connecte à votre serveur, elle doit seulement avoir un utilisateur ayant le même ID de User et de Group qu'un utilisateur du serveur pour avoir un accès total aux fichiers de cet utilisateur sur le serveur.


Cacher les Commandes Comprennant des Mots de Passe

Taper un mot de passe sur une ligne de commande peut poser un risque de sécurité compte tenu que le mot de passe sera sauvegardé dans l'historique des commandes de Bash, et pire, écrit dans le fichier historique.

Ajoutez cette ligne dans votre fichier de démarrage bash (/etc/profile, /etc/bashrc, ~/.bash_profile, ou ~/.bashrc) :

declare -x HISTCONTROL="ignorespace"

Une ligne de commande commençant par un espace ne sera pas ajoutée à l'historique. Ainsi, commencez toute commande comprenant un mot de passe par un espace en guise de précaution.


Supprimer des Lignes

Les astuces de cette semaine porteront sur sed, un utilitaire pratique permettant d'exécuter un script de commandes d'édition sur ses entrées.

Supprimer les lignes vides d'un fichier.

$ cat double-space
Ceci est un fichier avec

des lignes séparées par deux lignes vides


et quelques lignes vides supplémentaires

aussi.

Utilisez :

$ sed '/^$/d' double-space
Ceci est un fichier avec
des lignes séparées par deux lignes vides
et quelques lignes vides supplémentaires
aussi.

sed fonctionne en appliquant une expression régulière délimitée à chaque ligne d'entrée (^$ dans cet exemple). Si la ligne correspond alors sed applique les commandes d'édition qui suivent. 'd' supprime la ligne.

Voir les astuces des semaines 59 et 60 pour plus d'informations sur les expressions régulières.

Pour écrire le résultat dans le fichier d'origine, utilisez ce truc :

$ sed '/^$/d' double-space > tmp; mv tmp double-space

Supprimez les lignes contenant un texte spécifique. Utilisez la même technique avec une expression régulière appropriée. Cet exemple supprime toutes les lignes commençant par '$'.

$ sed '/^$/d' text

Rechercher des Lignes

Utilisez sed pour rechercher et afficher des lignes particulières, dans le style de grep.

En mode normal, sed renvoie les lignes d'entrée vers sa sortie. L'option '-n' annule ce comportement. La commande d'édition 'p' affiche chaque ligne qui correspond. La combinaison des deux indique à sed de n'afficher que les lignes correspondantes.

$ cat text
Ce fichier a un nombre
de lignes, don certaines contiennent
le mot don, et don d'autres
ne le contiennent pas.

$ sed -n '/don/p' text
de lignes, don certaines contiennent
le mot don, et don d'autres

Vous pouvez souhaiter éditer le contenu du fichier et n'afficher que les lignes modifiées :

$ sed -n 's/don/dont/p' text
de lignes, dont certaines contiennent
le mot dont, et dont d'autres

Rangée de Lignes

Modifiez une rangée de lignes avec sed.

Les exemples précédents ont utilisé une expression régulière pour trouver les lignes à modifier. sed peut aussi opérer sur une rangée de lignes ou sur une seule ligne.

Supprimez toutes les lignes entre le marqueur de début et le marqueur de fin inclus.

$ sed '/begin-marker/,/end-marker/d' filename

Ou afficher les :

$ sed -n '/begin-marker/,/end-marker/p' filename

Ou modifier les :

$ sed '/begin-marker/,/end-marker/s/don/dont/' filename

Si vous pensez que le terme 'don' puisse apparaître plus d'une fois sur une ligne, utilisez l'option 'g' (global) pour remplacer toutes les occurences d'une ligne.

$ sed '/begin-marker/,/end-marker/s/don/dont/g' filename

Edition Multiple

Appliquez une commande d'édition plusieurs fois sur une ligne.

Spécifiez des commandes multiples à sed en utilisant une de ces deux techniques.

Option -e:

$ cat this
this is this
and
that is that

$ sed -e 's/this/that/g' -e 's/that/twit/g' this
twit is twit
and
twit is twit

Séparez plusieurs commandes avec ';' :

$ sed 's/this/that/g;s/that/twit/g' this
twit is twit
and
twit is twit

Fichiers Script

Utilisez un fichier script si le script sed devient trop long ou trop complexe.

Ecrivez le script dans un fichier texte normal en plaçant chaque commande sur une ligne à part. Utilisez l'option '-f' pour spécifier un fichier script.

$ cat this
this is this
and
that is that

$ cat script
s/this/that/g
s/that/twit/g

$ sed -f script this
twit is twit
and
twit is twit

Imprimer/Supprimer des Lignes

Les astuces de cette semaine explorent Awk, un utilitaire pratique qui exécute un script de commandes d'édition passé en entrée. Reportez vous aussi aux astuces de la semaine précédente sur Sed qui présente des fonctions similaires.

Imprimer des lignes contenant un texte spécifique. Cet exemple imprime toutes les lignes commençant par '$'.

$ awk '/^$/{print($0)}' text

Supprimer les lignes blanches d'un fichier.

$ awk '/.+/{print($0)}' double-space

Pour enregistrer le résultat dans le fichier d'origine, utilisez cette astuce :

$ awk '/.+/{print($0)}' double-space > tmp; mv tmp double-space

Awk fonctionne en faisant correspondre chaque ligne passée en entrée à un modèle (dans ces exemples, une expression régulière '^$' pour les lignes commençant par '$', et '.+' pour les lignes contenant au moins un caractère). Si les lignes passées en entrée correspondent alors Awk applique les actions qui suivent et qui sont placées dans {...}. 'print($0)' imprime la ligne entière, comme le fait un simple 'print'.

Si aucun modèle n'est passé alors toutes les lignes correspondent. Si aucune action n'est donnée alors la ligne est imprimée. L'exemple du dessus peut être simplifié comme suit :

$ awk '/^$/' text

Notez que la différence entre imprimer et supprimer est une expression régulière inversée.

Voir les astuces des semaines 59 et 60 pour plus d'informations sur les expressions régulières.


Afficher des Champs

Affichez des champs spécifiques de chaque ligne correspondant aux critères.

L'astuce de Lundi utilisait l'action {print($0)}. $0 représente la ligne entière passée en entrée. $n représente le champ n. Les champs sont séparés par des espaces.

Une application commune revient à afficher des informations spécifiques provenant de la sortie de commandes Unix telles que la et ps.

Affichez juste le numéro pid (champ 1) :

$ ps ax | grep "[p]ostfix" | awk '{print($1)}'
437

Affichez le mois, la date et le nom de fichier à partir d'un long listing :

$ ls -l | awk '{print($6,$7,$9)}'

Sep 13 csv
Sep 13 double-space
Sep 13 many
Aug 30 script
Aug 30 text
Aug 30 this
Sep 13 xxx

Utilisez printf pour formatter la sortie :

$ ls -l | awk '{printf("Date: %s %s, File %sn",$7,$6,$9)}'
Date: , File
Date: 13 Sep, File csv
Date: 13 Sep, File double-space
Date: 30 Aug, File script
Date: 30 Aug, File text
Date: 30 Aug, File this
Date: 13 Sep, File xxx

La première ligne 'Date: , File' résulte de la première ligne affichée par ls -l. Cela peut être facilement retiré avec sed, grep ou awk.

Pour en savoir plus sur printf, se reporter à :

$ man 3 printf

Rangées de Lignes

Traitez une rangée de lignes avec Awk.

Les exemples précédents ont utilisé une expression régulière pour filtrer les lignes. Awk peut être appelé pour traiter une rangée de lignes ou une seule ligne.

Affichez toutes les lignes entre begin-marker et end-marker compris.

$ cat text
Ce fichier a un nombre
begin-marker
de lignes, dont certaines contiennent
le mot don, et dont certaines
end-marker
ne le contiennent pas.

$ awk '/begin-marker/,/end-marker/{print $0}' text
begin-marker
de lignes, dont certaines contiennent
le mot don, et dont certaines
end-marker

Ou simplement :

$ awk '/begin-marker/,/end-marker/' text

Commandes Multiples

Executez plusieurs commandes pour chaque ligne en entrée.

Séparatez les commandes avec ';' et toutes les commandes seront exécutées pour chaque ligne répondant aux critères.

Pour afficher la longueur de chaque ligne et la ligne elle-même, utilisez :

$ awk '{print(length($0)); print}' text
22
Ce fichier a un nombre
12
begin-marker
...

Cela pourrait être effectué avec une seule instruction print mais cela illustre l'utilisation de commandes multiples.

En développant l'astuce de Mercredi, nous pouvons afficher des lignes qui sont en dehors d'une rangée spécifique :

$ awk '/begin-marker/,/end-marker/ {next}; {print}' text
Ce fichier a un nombre
ne le contiennent pas.

Les lignes correspondant aux critères exécutent 'next', ce qui saute la ligne. Les lignes ne correspondant pas ne l'exécutent pas, donc 'print' est exécutée. Notez que c'est différent du premièr exemple où deux commandes étaient appliquées au même modèle de recherche :

/pattern/{command1; command2}

Ici, nous appliquons la première commande au premier modèle et la seconde commande aux deuxième modèle (qui est vide pour s'appliquer à toutes les lignes).

/pattern1/{command1}; /pattern2/{command2}

Cela ne marche pas :

$ awk '/begin-marker/,/end-marker/ {next; print}' text

Modèles Multiples

Specifiez plusieurs modèles à appliquer à chaque ligne répondant aux critères :

$ cat many
line one
the second line
and the third
the fourth
line five
the six
and the last line

$ awk '/^the//^line/' many
line one
the second line
the fourth
line five
the six

Appliquer une commande différente à chaque modèle :

$ awk '/^the/{printf("THE: %sn",$0)}; /^line/{printf("LINE: %sn",$0)}' many
LINE: line one
THE: the second line
THE: the fourth
LINE: line five
THE: the six

Appliquer une commande aux lignes qui correspondent à un modèle ou à un autre en utilisant l'opérateur 'or' (||) :

$ awk '/^the/||/^line/{printf("MATCHED: %sn",$0)}' many
MATCHED: line one
MATCHED: the second line
MATCHED: the fourth
MATCHED: line five
MATCHED: the six

Appliquer une commande aux lignes qui correspondent aux deux modèles en utilisant l'opérateur 'and' (&&) :

$ awk '/the/&&/line/{printf("MATCHED: %sn",$0)}' many
MATCHED: the second line
MATCHED: and the last line

Lecture des Fichiers CSV

Voir la semaine 86 pour une introduction à AWK.

Changez le séparateur de champ par défaut utilisé par Awk.

Les fichiers à valeurs séparées par des virgules ('Comma Separated Value') représentent un moyen populaire d'exporter des tables de données (les tableurs peuvent exporter au format CSV). Par exemple :

$ cat csv
scott,sheppard,mr,editor in chief,01
adrian,mayo,mr,editor,02
jan,forbes,miss,goddess,69

Awk utilisera normalement des espaces comme séparateur de champ. Pour changer cela, utilisez l'option -F :

awk -F "," '{print $2,$4}' csv
sheppard editor in chief
mayo editor
forbes goddess

Autrement, nous pouvons changer la variable Awk 'FS' en utlisant BEGIN.

$ awk 'BEGIN {FS=","} {print $2,$4}' csv
sheppard editor in chief
mayo editor
forbes goddess

Les commandes dans {...} qui suivent BEGIN sont exécutées avant que le script Awk ne démarre.

Le séparateur de champ est en fait une expression régulière et peut accepter une liste de séparateurs ou des jokers classiques d'expressions.

$ cat csv2
scott:sheppard,mr,editor in chief-01
adrian:mayo,mr,editor-02
jan:forbes,miss,goddess-69

$ awk 'BEGIN {FS=",|:|-"} {printf "1=%s, 2=%s, 3=%s, 4=%s, 5=%sn",$1, $2, $3, $4, $5}' csv2
1=scott, 2=sheppard, 3=mr, 4=editor in chief, 5=01
1=adrian, 2=mayo, 3=mr, 4=editor, 5=02
1=jan, 2=forbes, 3=miss, 4=goddess, 5=69

Edition avec Awk

Jusqu'à présent, les examples (y compris ceux de la semaine 86) ont utilisé Awk pour filtrer mais pas pour éditer. La semaine 85 montrait comment utiliser 'sed' pour éditer des fichiers. Awk peut aussi éditer des fichiers.

Chercher et remplacer avec Awk.

$ cat text
This file is one witch has a number
begin-marker
of lines, some of witch contain
the word witch, and some of witch
end-marker
do not.

$ awk -v t=which '/begin-marker/,/end-marker/ {sub('/witch/', t, $0); print $0}' text
begin-marker
of lines, some of which contain
the word which, and some of witch
end-marker

Cet exemple applique le script {sub('/witch/', t, $0); print $0} à chaque ligne situées entre les marqueurs. 'sub' est une fonction qui substitue son modèle (witch) par la valeur d'une variable (t), sur son troisième paramètre. Dans ce cas, $0 représente la ligne entière mais le champ n pourrait aussi être spécifié en utilisant $n. La variable t est positionnée sur 'which' en utilisant l'option de ligne de commande -v.

Notez que seule la première occurence du modèle 'witch' de chaque ligne est substituée. Pour substituter tous les modèles d'une ligne, utilisez 'gsub'. (Global SUBstitute)


Compter les Lignes

Comptez les lignes et plus encore.

Awk utilise des variables comme tout autre langage. Cet exemple utilise une arithmetique simple pour compter le nombre de lignes d'un fichier :

$ cat text
This file is one witch has a number
begin-marker
of lines, some of witch contain
the word witch, and some of witch
end-marker
do not.

$ awk 'BEGIN {n=0} {n=n+1} END {printf ("Total lines in file %dn", n)}' text
Total lines in file 6

{n=0} est exécuté une fois au début du script par l'instruction BEGIN. {n=n+1} est exécutée sans condition pour chaque ligne. END {...} exécute ses instructions une seule fois à la fin du script.

Voici un autre exemple qui affiche aussi le nombre de lignes commençant par 'the' et la valeur du deuxième champ :

$ awk 'BEGIN {n=0} /^the/{printf("Line %d: %sn", n, $2)} {n=n+1} END {printf ("Total lines in file %dn", n)}' text
Line 3: word
Total lines in file 6

Utiliser un Fichier Script

Des scripts Awk complexes peuvent être placés dans un fichier. Répétons l'astuce de Mercredi en utilisant un fichier script :

$ cat awk-script
BEGIN {n=0}
/^the/{printf("Line %d: %sn", n, $2)}
{n=n+1}
END {printf ("Total lines in file %dn", n)}

Chaque instruction est placée dans une nouvelle ligne du fichier script. Utilisez l'option '-f' pour indiquer à Awk de lire son script dans un fichier :

$ awk -f awk-script text
Line 3: word
Total lines in file 6

Plus de Puissance

Awk est un langage de programmation complet doté d'instructions C telles que 'for', 'while' et 'if'.

En trois exemplaires :

$ cat file
line 1
line 2

$ awk '{for (i = 0; i < 3; i++) print $0}' file
line 1
line 1
line 1
line 2
line 2
line 2

Voici un exemple utilisant l'instruction 'if' :

$ cat posts
Maio 34 posts
Forbes 35 posts
Sheppard 12 posts
Trevor 345678 posts
Hollis 17 posts

$ cat awk-script
BEGIN { print "More than 34 posts"; max = 0; name = ""}
{if ($2 > 34) print $0}
{if ($2 > max) {max = $2; name = $1}}
END { printf ("Max posts %d by %sn", max, name); print "---n"}

$ awk -f awk-script posts
More than 34 posts
Forbes 35 posts
Trevor 345678 posts
Max posts 345678 by Trevor
---

Réparer les Disques

Utilisez diskutil pour vérifier et réparer les disques. Pour le réparer, le disque ne doit pas être utilisé et diskutil doit être lancé sous root.

Par exemple, utilisez df pour trouver le node du périphérique :

$ df
Filesystem            Size  Used Avail Use% Mounted on
/dev/disk0s3           12G  6.5G  5.9G  53% /
/dev/disk0s5           12G  3.4G  9.1G  27% /Users
/dev/disk0s7          5.9G  578M  5.3G  10% /Games
/dev/disk0s9          5.9G   21M  5.8G   1% /Music

(ou 'diskutil list')

puis :

$ diskutil verifyDisk /dev/disk0s7
Started verify/repair on disk disk0s7 Games-saruman
Checking HFS Plus volume.
Checking Extents Overflow file.
Checking Catalog file.
Checking Catalog hierarchy.
Checking volume bitmap.
Checking volume information.
The volume Games-saruman appears to be OK.
Verify/repair finished on disk disk0s7 Games-saruman

Ou utilisez le point de montage (en général /Volumes/name) :

$ diskutil verifyDisk /Games

Utilisez 'diskutil repairDisk' pour la réparation.


Réparer les Autorisations

Utilisez diskutil pour vérifier et réparer les autorisations d'un fichier sur le disque système. Vous ne pouvez spécifier qu'un volume de démarrage OS X et, pour la réparation, la commande diskutil doit être lancée sous root.

Si vous rencontrez des problèmes avec des fonctions systèmes ou des applications ne se comportant pas correctement, vérifiez et réparez les autorisations.

Utilisez df pour trouver le node du périphérique, comme dans l'astuce de Lundi, ou spécifiez le point de montage, puis :

$ diskutil verifyPermissions /dev/disk0s3
Started verify/repair permissions on disk disk0s3 OSX-saruman
Determining correct file permissions.
...

Pour la réparation du volume de démarrage classic en cours utilisez :

$ diskutil repairOS9Permissions
You cannot repair OS 9 permissions on this machine (No Classic folders found)

OK, je n'ai pas OS 9 sur ma machine :-)


Vérifier les Préférences

Vérifiez tous les fichiers de préférence .plist situés dans ~/Library/preferences.

Si une application dérape, cela peut être du à un fichier de préférences corrompu. Utilisez la commande 'plutil' pour vérifier le fichier de préférence.

$ plutil -lint ~/Library/Preferences/com.apple.iChat.plist
/Users/saruman/Library/Preferences/com.apple.iChat.plist: OK

Cela ne fera que vérifier la syntaxe du fichier mais pas les données que seule l'application ne peut comprendre.

Pour vérifier toutes les préférences :

$ find ~/Library/Preferences -name "*.plist" -print0 | xargs -n1 -0 plutil -lint

(Cela utilise -print0 et -0 pour s'arranger des espaces dans les noms de fichier)


Ménage Périodique

OS X nettoie le système de fichiers en supprimant les vieux fichiers temporaires, en compressant et effaçant les fichiers log, en retirant les messages système anciens, en sauvegardant la base de données NetInfo, en mettant à jour la base de données 'locate', et plus encore...

La maintenance périodique du système est programmée par 'cron' qui lance un programme appelé 'periodic'.

% cat /etc/crontab
...
#minute hour  mday  month  wday  who   command
# Run daily/weekly/monthly jobs.
15      3     *     *      *     root  periodic daily
30      4     *     *      6     root  periodic weekly
30      5     1     *      *     root  periodic monthly
...

The daily script is run at 3:15 am. The weekly script is run at 4:30 am Saturday. The monthly script is run at 5:30 am on the first of each month.
The output from these scripts can be found in:
% ls /var/log/*.out /var/log/daily.out /var/log/monthly.out /var/log/weekly.out

Periodic scrute /etc/periodic/parameter-given-periodic et exécute tous les scripts de ce répertoire.

lancez les scripts de maintenance manuellement :

% sudo periodic daily
% sudo periodic weekly
% sudo periodic monthly

Autrement, éditez /etc/crontab et choisissez l'heure à laquelle votre Mac sera actif :

Si vous souhaitez ajouter vos propres tâches de maintenance - quotidiennes, hebdomadaires ou mensuelles - créez alors les fichiers suivants autant que nécessaire.

/etc/daily.local
/etc/weekly.local
/etc/monthly.local

Ce sont des scripts shell classiques et une fois créés ils sont lancés automatiquement par les scripts 'daily', 'weekly' et 'monthly'.

Ces fichiers ne seront pas écrasés par les mises à jour système qui peuvent affecter les fichiers situés dans /etc/periodic.


Commandes de Pilotage du Système de Fichiers

Utilisez des commandes pour suivre ce qui arrive dans le système de fichiers.

Utilisez fs_usage pour rapporter les appels système en temps réel. Par exemple, pour rapporter toute l'activité fs dans un fichier log :

$ fs_usage -f filesys > log

Pour suivre juste l'activité fs du démon maître posfix :

$ fs_usage -w -f filesys master

fs_usage doit être lancé sous root.

Une commande similaire, sc_usage, suit tous les appels système.

Utilisez fstat pour connaître les fichiers ouverts. Par exemple, pour suivre les fichiers ouverts par l'utilisateur saruman :

$ fstat -u saruman

Pour suivre les fichiers au fûr et à mesure qu'ils sont ouverts, utilisez lsof.


...Les Conditions Shell

Cette semaine fait la lumière sur des problèmes communs que l'on peut rencontrer avec les scripts et les commandes shell en illustrant où se trouve le problème et comment le corriger.

Une commande appelée 'test', aussi connue en tant que '[', permet à qui conque de faire toute sorte de tests et de comparaisons impliquant des fichiers, des chaînes et des nombres.

Se reporter à la semaine 82 et à :

$ man test

ou

$ man [

On peut comparer des chaînes pour tester celle qui vient en premier d'un point de vue alphabétique :

$ if [ "aaa" > "zzz" ]; then echo "Yes"; else echo "No"; fi
Yes

Et pourquoi 'Yes' ? "aaa" n'est pas > "zzz".

Le shell interprête '>' comme un cacartère de redirection, il doit donc être échappé :

$ if [ "aaa" \> "zzz" ]; then echo "Yes"; else echo "No"; fi
No

La première version aurait créer un fichier nommé "zzz". Peut-être que si nous avions essayé l'exemple suivant en premier, cela nous aurait éclairé sur ce qui se serait passer.

$ if [ "zzz" < "aaa" ]; then echo "Yes"; else echo "No"; fi
bash: aaa: No such file or directory
No

Les guillemets peuvent aussi être utilisées pour échapper :

$ if [ "zzz" "<" "aaa" ]; then echo "Yes"; else echo "No"; fi
No
$ if [ "aaa" "<" "zzz" ]; then echo "Yes"; else echo "No"; fi
Yes
$

Essayons donc avec des nombres :

$ if [ 7 ">" 2 ]; then echo "Yes"; else echo "No"; fi
Yes

Comme prévu, mais qu'advient il avec cela :

$ if [ 17 ">" 2 ]; then echo "Yes"; else echo "No"; fi
No

L'opérateur '>' fonctionne sur des chaînes (ou des nombres qui sont interprêtés comme des chaînes). Pour les comparaisons numériques il faut utiliser '-gt' et '-lt' :

$ if [ 17 -gt 2 ]; then echo "Yes"; else echo "No"; fi
Yes

...Les Conditions Bash

Bash est doté de l'opérateur arithmétique très utile $((...)). Se reporter au Jeudi de la Semaine 82..

$ echo $((2+7))
9

$ $( ((2>7)) )
$ echo $?
1

$ $( ((2<7)) )
$ echo $?
0

Pour interprtêter le résultat des deux conditions, en langage shell 0 représente TRUE (vrai) et 1 représente FALSE (faux).

La construction évalue les expressions et les expressions relationnelles. Elle peut aussi prendre des $variables tout comme des valeurs litérales telles que 7.

Essayez ceci :

$ if $((2<7)); then echo "Yes"; else echo "No"; fi
bash: 1: command not found
No

So why '1: command not found'?

Une erreur commune consiste à utiliser $((...)) dans une condition. $ exécute effectivement l'expression pour retourner la valeur (1), mais l'instruction 'if' le fait aussi. Une instruction 'if' exécute la commande qui la suit immediatement (souvent '[ ... ]'), et essaies donc d'exécuter '1' (pourquoi retourne t'elle 1 et pas 0 alors ?) renvoyé par l'évaluation de '2<7'.

Enlever le $:

$ if ((2<7)); then echo "Yes"; else echo "No"; fi
Yes

Les exemples suivants sont plus compliqués mais fonctionnent aussi. Vous pouvez voir pourquoi ils fonctionnent si vous avez compris l'explication précédente.

$ if (($((2<7))==1)); then echo "Yes"; else echo "No"; fi
Yes
$ if [ $((2<7)) -eq 1 ]; then echo "Yes"; else echo "No"; fi
Yes
$ if [ $((7<2)) -eq 1 ]; then echo "Yes"; else echo "No"; fi
No

...Les Noms de Fichier

J'ai essayé cette commande :

$ cd ~/Library/Preference
$ /bin/ls *.plist
ls: illegal option -- .
usage: ls [-ABCFGHLPRSTWZabcdfghiklnoqrstuvx1] [file ...]

Bizarre - que se passe t'il ici ? La réponse tient dans le message 'illegal option'. J'ai un fichier qui s'appelle :

-BringToFront.plist

Le shell développe *.plist. Lorsque une commande comporte un * non échappé, c'est le shell qui l'interprête et le développe, pas la commande à laquelle il est passé. Donc, la commande vue par 'ls' est :

ls -BringToFront.plist Fire.plist Vim.plist ...

-BringToFront.plist semble être une liste d'options pour 'ls'.

Donc, comment contourner cela ? Le caractère '*' ne peut évidemment être échappé : il ne serait pas développé par le shell et 'ls' ne comprendrait pas.

$ ls "*.plist"
ls: *.plist: No such file or directory

La pluspart des commandes acceptent l'option spéciale '--' qui veut dire 'fin des options'. Tout ce qui suit est interprêté comme argument pas comme une option.

$ ls -- *.plist
-BringToFront.plist
Fire.plist
Vim.plist
...

Lorsque l'on spécifie directement un nom de fichier on peut rencontrer des difficultés similaires :

$ ls -- -*
-i
$ rm -i
usage: rm [-f | -i] [-dPRrvW] file ...
       unlink fil

Soit vous spécifiez le nom de fichier avec un préfixe de chemin d'accès pour cacher le '-', soit vous utilisez '--' une fois de plus :

$ rm ./-i
$ rm -- -i

Certaines versions d'Unix comprennent la commande primitive 'unlink', qui n'accepte aucune option et ainsi n'est pas dérangée par des noms de fichiers commençant par '-'...

$ unlink -i
-bash: unlink: command not found

...mais pas OS X.


...Les Conditions Shell Complexes

La commande 'test' ou '[' peut accepter 'and' et 'or'. '-a' signifie 'and', '-o' signifie 'or'. Voir Vendredi de la Semaine 82.

Il est souvent nécessaire d'utiliser ( ... ) pour forcer un ordre correct d'évaluation. Dans cet exemple nous voulons :

A and (B or C)

$ if [ 1 -eq 0 -a ( 1 -eq 1 -o 1 -eq 1 ) ]; then echo "Yes"; else echo "No"; fi
-bash: syntax error near unexpected token `('

Le shell bash interprête les parenthèses et ne les passent pas à 'test'.

Nous pourrions essayer d'échapper l'expression entière en l'entourant avec des guillemets :

$ if [ "1 -eq 0 -a ( 1 -eq 1 -o 1 -eq 1 )" ]; then echo "Yes"; else echo "No"; fi
Yes

Cette réponse est en réalité mauvaise, elle devrait être 'no' (FAUX et (VRAI ou VRAI) = FAUX). Pourquoi cela donne t'il la mauvaise réponse ? Parce que nous passons maintenant une chaîne à 'test', pas une expression, et une chaîne donne VRAI (ou FAUX pour une chaîne vide).

Le secret consiste à échapper chaque parenthèse, ainsi l'expression est passée à 'test' sous forme d'expression pas sous forme de chaîne.

$ if [ 1 -eq 0 -a \( 1 -eq 1 -o 1 -eq 1 \) ]; then echo "Yes"; else echo "No"; fi
No

Commandes NetInfo

Cette semaine nous présentons des scripts utiles pour gérer les comptes utilisateurs en ligne de commande : ajouter un nouvel utilisateur, un nouveau groupe et ajouter un utilisateur existant à un groupe.

Il y a plein de commandes pour interroger et changer la base de données NetInfo, deux des plus utiles étant :

dscl - Directory Services Command Line

Une alternative au vieux niutil qui manipule les données de NetInfo et en fait dans chaque noeud Directory Services.

Par exemple, pour ajouter un nouvel utilisateur :

$ dscl . create /users/joe

et pour ajouter des paires propriété-valeur :

$ dscl . create /users/joe name joe
$ dscl . create /users/joe shell /bin/bash
$ dscl . create /users/joe realname "joe jones"

Tout sous-répertoire NetInfo peut être créé, et les paires propriété-valeur ajoutées, de la même façon.

nireport - Print tables from NetInfo

Cela affiche les valeurs des propriétés listées pour les répertoires NetInfo spécifiés.

Par exemple, listez tous les utilisateurs :

$ nireport . /users name
nobody
root
daemon
unknown
smmsp
lp
postfix
...

Listez tous les noms de groupe et leur ID :

$ nireport . /groups name gid
nobody -2
nogroup -1
wheel 0
daemon 1
kmem 2
sys 3
tty 4
...

D'autres commandes :

nifind, nigrep, niload, nidump

En mode mono utilisateur, lorsque NetInfo ne tourne pas, utilisez nicl.

Elles sont toute documentées dans le manuel Unix.

Mardi donnera quelques astuces pratiques pour interroger la base NetInfo, tandis que Mercredi, Jeudi et Vendredi donneront des scripts pour ajouter de nouveaux utilisateurs et groupes à NetInfo et ajouter des utilisateurs dans des groupes.


Interroger NetInfo

Voici quelques astuces sur l'utilisation de nireport pour extraire des informations sur les utilisateurs et les groupes de NetInfo. Ces exemples peuvent être utilisés dans des scripts Bash.

Vérifier qu'un utilisateur existe :

$ user=jan
$ if [ ! -z "$(nireport . /users name | grep -w $user)" ]; then echo "Exists"; fi
Exists

$ user=xxxx
$ if [ ! -z "$(nireport . /users name | grep -w $user)" ]; then echo "Exists"; fi
root@saruman ~/bin
$

Vérifier qu'un utilisateur est dans un groupe (utilisateurs root puis jan dans le groupe admin):

$ group=admin
$ user=root
$ in=$(nireport . /groups name users | grep -w "$group.*$user"); if [ ! -z "$in" ]; then echo "In group"; fi
In group

$ user=jan
$ in=$(nireport . /groups name users | grep -w "$group.*$user"); if [ ! -z "$in" ]; then echo "In group"; fi
$

Convertir un nom de groupe en GID :

$ group=admin
$ echo "$(nireport . /groups gid name | grep $group | cut -f 1)"
80

Vérifier que c'est le groupe primaire d'un utilisateur :

$ user=jan
$ group=jan
$ gid="$(nireport . /groups gid name | grep $group | cut -f 1)"

$ pri=$(nireport . /users name gid | grep -w "$user[[:space:]].*$gid"); if [ ! -z "$pri" ]; then echo "Primary group"; fi
Primary group

$ user=jan
$ group=admin
$ gid="$(nireport . /groups gid name | grep $group | cut -f 1)"

$ pri=$(nireport . /users name gid | grep -w "$user[[:space:]].*$gid"); if [ ! -z "$pri" ]; then echo "Primary group"; fi
$

Obtenir le UID et le GID d'un utilisateur :

$ user=jan
$ nireport . /users name uid gid | grep $user
jan 520 520

Ajouter un nouvel utilisateur

Ce script ajoute un nouveau compte utilisateur à OS X. Indiquez le nom et prénom de l'utilisateur, l'ID désiré, et s'il doit être normal (staff) ou administrateur.

L'ID est fourni car une création normale de compte sous OS X ne permet pas cette option. Le nom raccourci de l'utilisateur sera égal à son nom. Un répertoire 'home' sera créé et ainsi l'utilisateur sera un propriétaire complet de compte OS X et pourra se connecter de manière normal.

Le script demandera un mot de passe pour l'utilisateur.

Pas mal de vérifications sont effectuées comme vous pouvez le voir dans les commentaires du script.

Allez chercher le script ici.

NOTE: CE SCRIPT A ETE ECRIT POUR PANTHER (10.3)

#!/bin/bash

# Créer un utilisateur. # Prend le nom de l'utilisateur (=shortname), prénom, uid et staff|admin # et crée : # un nouvel utilisateur dans passwd NetInfo # un nouveau répertoire départ /Users/firstname
usage () { echo "Créer un nouvel utilisateur staff ou admin" echo "Utilisation : ${0##*/} prénom nom uid staff|admin" if [ "$*" != "" ]; then echo " Erreur : $*"; fi exit 1 }

# Le script doit être lancé par root # if [ "$USER" != "root" ]; then echo "Doit être lancé par root." exit 1 fi

# Vérification des paramètres # if [ $# -ne 4 ]; then usage fi
first=$1; last=$2; uid=$3; accnt=$4
# Vérifie que les utilisateurs n'ont pas déjà un répertoire départ if [ -e /Users/$first ]; then usage "L'utilisateur $first existe déjà dans /Users/$first" fi
# Recherche dans NetInfo l'utilisateur donné - il ne doit pas exister str="$(nireport . /users name | grep -w $first)" if [ ! -z "$str" ]; then usage "L'utilisateur $first existe déjà (mais n'a pas de répertoire départ)" fi
# Recherche dans NetInfo le uid donné - il ne doit pas exister str="$(nireport . /users uid | grep -w $uid)" if [ ! -z "$str" ]; then usage "L'ID utilisateur $uid existe déjà" fi
# Recherche dans NetInfo le groupe donné - il ne doit pas exister str="$(nireport . /groups name | grep -w $first)" if [ ! -z "$str" ]; then usage "Le Groupe $first existe déjà" fi
# Recherche dans NetInfo le gid donné - il ne doit pas exister str="$(nireport . /groups gid | grep -w $uid)" if [ ! -z "$str" ]; then usage "Le Groupe ID $uid existe déjà" fi
# Vérifie que staff ou admin a été passé if [ $4 != staff ] && [ $4 != admin ]; then usage "Donnez au compte le type 'staff' ou 'admin'" fi

# Ajoute le nouvel utilisateur à NetInfo # # Ajoute l'utilisateur et les propriétés essentielles dscl . create /users/$first dscl . create /users/$first name $first dscl . create /users/$first passwd "*" dscl . create /users/$first hint "" dscl . create /users/$first uid $uid dscl . create /users/$first gid $uid dscl . create /users/$first home /Users/$first dscl . create /users/$first shell /bin/bash dscl . create /users/$first realname "$first $last" dscl . create /users/$first picture "/Library/User Pictures/Fun/Smack.tif" dscl . create /users/$first sharedDir Public
# ajoute quelques propriétés supplémentaires dans NetInfo dscl . create /users/$first _shadow_passwd "" dscl . create /users/$first _writers_hint $first dscl . create /users/$first _writers_real_name $first
# ajoute le nouveau groupe dscl . create /groups/$first dscl . create /groups/$first name $first dscl . create /groups/$first passwd "*" dscl . create /groups/$first gid $uid
echo "Nouvel utilisateur et groupe $first créés"

# Ajoute les utilisateurs admin au groupe admin # if [ $4 = admin ]; then dscl . merge /groups/admin users $first dscl . merge /groups/appserverusr users $first dscl . merge /groups/appserveradm users $first echo "$first ajouté aux groupes admin, appserverusr, appserveradm" fi

# Crée le répertoire départ, le remplit à partir d'un modèle et positionne le propriétaire # mkdir /Users/$first if [ ! -d /Users/$first ]; then echo "Impossible de créer le répertoire /Users/$first" exit fi
ditto -rsrc /System/Library/User Template/English.lproj/ /Users/$first chown -R ${first}:$first /Users/$first echo "Répertoire départ /Users/$first créé et remplit"

# Donne un mot de passe à l'utilisateur # echo "Un mot de passe pour ce compte doit être donné, il est actuellement à blanc" passwd $first
exit 0

Ajouter un nouveau Groupe

Ce script ajoute un nouveau groupe à OS X. Il faut lui passer le nom et l'id du groupe. Le groupe sera créé sans aucun utilisateur lui appartenant. Ajouter des utilisateurs au groupe avec add-user2group (attendre Vendredi).

Pas mal de vérifications sont effectuées comme vous pouvez le voir dans les commentaires du script.

Allez chercher le script ici.

NOTE: CE SCRIPT A ETE ECRIT POUR PANTHER (10.3)

#!/bin/bash

# Création d'un groupe. # Prend un nom et un id de groupe et crée le nouveau groupe dans les groupes NetInfo
usage () { echo "Création d'un nouveau groupe" echo "Usage: ${0##*/} groupname gid" if [ "$*" != "" ]; then echo " Erreur : $*"; fi exit 1 }

# Doit être lancé par root # if [ "$USER" != "root" ]; then echo "Ce script doit être lancé par root." exit 1 fi

# Vérification des paramètres # if [ $# -ne 2 ]; then usage fi
group=$1; gid=$2
# Recherche dans NetInfo le groupe donné - il ne doit pas exister str="$(nireport . /groups name | grep -w $group)" if [ ! -z "$str" ]; then usage "Le Groupe $group existe déjà" fi
# Recherche dans NetInfo le gid donné - il ne doit pas exister str="$(nireport . /groups gid | grep -w $gid)" if [ ! -z "$str" ]; then usage "Le Groupe ID $gid existe déjà" fi

# Ajoute le nouveau groupe à NetInfo # # Ajoute le groupe et des propriétés essentielles dscl . create /groups/$group dscl . create /groups/$group name $group dscl . create /groups/$group passwd "*" dscl . create /groups/$group gid $gid #dscl . create /groups/$group users "" breaks add-user2group if added as a blank value
echo "Le nouveau groupe $group a été créé" echo "Ajoutez maintenant de nouveaux utilisateur avec add-user2group"
exit 0

Ajouter des Utilisateurs à un Groupe

Ce script ajoute un ou plusieurs utilisateurs à un groupe. Passez lui le nom du groupe et une liste de noms raccourcis d'utilisateur.

Pas mal de vérifications sont effectuées comme vous pouvez vous en rendre compte dans les commentaires du script.

Allez chercher le script ici.

NOTE: CE SCRIPT A ETE ECRIT POUR PANTHER (10.3)

#!/bin/bash

# Ajout de nouveaux utilisateurs à un groupe.
# Ajoute un utilisateur (ou plusieurs) à un groupe existant dans NetInfo

usage () { echo "Ajouter un utilisateur (ou plusieurs) à un groupe existant" echo "Usage: ${0##*/} group user [user...]" if [ "$*" != "" ]; then echo " Erreur : $*"; fi exit 1 }

# Lancé par root ? # if [ "$USER" != "root" ]; then echo "Ce script doit être lancé par root." exit 1 fi

# Vérfication des paramètres # if [ $# -lt 2 ]; then usage fi
group=$1
# Recherche le groupe donné dans NetInfo - il doit exister str="$(nireport . /groups name | grep -w $group)" if [ -z "$str" ]; then usage "Le Groupe $group n'existe pas" fi
# Obtient le numéro du groupe à partir du nom gid="$(nireport . /groups gid name | grep $group | cut -f 1)"
# Boucle de lecture des paramètres (utilisateurs) à ajouter au groupe # shift
for user in $*; do # Vérifie que l'utilisateur existe struser="$(nireport . /users name | grep -w $user)" # Vérifie si l'utilisateur n'est pas déjà présent dans le groupe stringroup=$(nireport . /groups name users | grep -w "$group[[:space:]].*$user") # Vérifie si le groupe est le groupe primaire de l'utilisateur strprimary=$(nireport . /users name gid | grep -w "$user[[:space:]].*$gid")
#echo "Utilisateur $struser, dans le groupe $stringroup, primaire $strprimary"
# Vérifie que l'utilisateur existe... if [ -z "$struser" ]; then echo "Utilisateur $user inexistant" # ...et qu'il n'appartient pas déjà au groupe... elif [ ! -z "$stringroup" ]; then echo "Utilisateur $user déjà présent dans le groupe $group - aucun ajout effectué" # ...et que ce n'est pas le groupe primaire elif [ ! -z "$strprimary" ]; then echo "Ce groupe ets le groupe primaire de l'Utilisateur - aucun ajout effectué" else # Ajout de l'Utilisateur au groupe dscl . merge /groups/$group users "$user" echo "$user ajouté au groupe $group" fi done
exit 0

Exécutables comme Conditions

Ces exemples sont écrits pour le shell Bash. Ils sont applicables à d'autres shells mais la syntaxe peut nécessiter quelques modifications. La forme $(...) doit être remplacée par `...` sous tcsh.

Voir aussi la semaine 56 et la semaine 65.

Incorporez le résultat de l'exécution d'une commande dans une condition.

Par exemple, j'ai récemment eu à écrire un script qui devait attendre (dans une boucle) qu'un volume particulier soit monté. 'df | grep' est une manière facile de tester cela :

$ volname=Games
$ df | grep $volname
/dev/disk0s7 5.9G 578M 5.3G 10% /Games

La technique consiste à boucler tant que la sortie de la commande ci-dessus est nulle. Notez que '[ -z string ]' est vraie lorsque la chaîne a une longueur de zéro (null).

Essai 1 :

$ while [ -z df | grep $volname ]; do echo -n "."; done
-bash: [: missing `]'
grep: ]: No such file or directory

'[' attend une chaîne, nous devons donc capturer la sortie de la commande 'df | grep $volname' et tester cette chaîne.

Essai 2 :

$ while [ -z $(df | grep $volname) ]; do echo -n "."; done
-bash: [: too many arguments

La sortie de grep est une chaîne contenant des espaces, nous devons donc entourer la chaîne de guillemets de façon à ce qu'elle soit présentée à '[ -z ... ]' comme une seule chaîne.

Utilisez "$(...)" pour retourner une seule chaîne à partir de la sortie d'une commande ou d'un pipe :

$ while [ -z "$(df | grep $volname)" ]; do echo -n "."; sleep 2; done;
.....

Ceci boucle jusuq'à ce que le volume $volname apparaisse.

Notez que 'echo -n' est utilisé pour éviter une nouvelle ligne pour chaque point.

Utilisez 'sleep n' dans le corps d'une boucle d'attente pour éviter de consommer du temps CPU. 'n' est en secondes.


Guillemets Trompeuses

Suite de l'astuce de Lundi.

Savoir utiliser les guillemets dans les guillemets.

Supposez qu'un nom de volume comprennent des espaces (ou des caractères shell spéciaux).

$ volname="New Games"
$ while [ -z "$(df | grep $volname)" ]; do echo -n "."; sleep 2; done; echo
grep: Games: No such file or directory
.^C

Nous devons entourer $volname de guillemets. Mais, comme l'expression:

"$(df | grep $volname)"

est déjà entourée de guillemets, comment pouvons placer aussi $volname entre guillemets ? L'utilisation d'apostrophes '...' pour la partie externe ne marchera pas car le shell ne pourra interprêter '$(...)'.

Vous pouvez vous attendre à ce que ceci fonctionne :

$ while [ -z "$(df | grep \"$volname\")" ]; do echo -n "."; sleep 2; done; echo
grep: Trailing backslash
.grep: Trailing backslash

Cela ne marche pas car Bash se comporte de manière assez ingénieuse. A l'intérieur de "$(...)" Bash reconsidère son approche des guillemets imbriquées et la solution très simple est :

$ while [ -z "$(df | grep "$volname")" ]; do echo -n "."; sleep 2; done; echo
......

Mercredi apporte une seconde solution.


Guillemets entre Guillemets

Cette astuce pratique n'est pas toujours évidente tant qu'elle n'est pas montrée du doigt.

Cela devrait être évident :

$ word=Hi

$ echo "He said $word"
He said Hi

$ echo $word
Hi

$ echo '$word'
$word

Comment interprêter la sortie de cette commande ?

$ echo "He said '$word'"

Tester une Variable Numérique

Bash ne semble pas fournir de commodité pour tester si une variable est numérique ('123' opposé à 'abc' ou 'a2').

Voici deux manières indirectes de faire ce test. Si vous connaissez de meilleures méthodes, faites le moi savoir.

La première technique utilise grep et une expression régulière pour rechercher une chaîne faite de chiffres. Si la chaîne n'est pas des chiffres, grep renvoi une chaîne nulle, qui est interprêtée en tant que fausse.

$ var=12
$ if [ "$(echo $var | grep "^[[:digit:]]*$")" ]; then echo number; fi
number

La seconde technique repose sur 'test' (ou '[') renvoyant une erreur et le code '2' si -eq n'a pas été valorisé avec une valeur numérique. Sinon, '0' ou '1' est retourné pour TRUE ou FALSE.

$ var="123"
$ [ $var -eq 0 ] 2> /dev/null
$ if [ $? -eq 0 -o $? -eq 1 ]; then echo number; fi
number
$

$ var="12AB"
$ [ $var -eq 0 ] 2> /dev/null
$ if [ $? -eq 0 -o $? -eq 1 ]; then echo number; fi
$

Variables Variables

Bash peut implémenter des variables variables, d'une façon détournée. Les programmeurs PHP programmers seront habitués aux variables variables.

De manière basique, nous voulons construire un nom de variable à partir d'une autre variable:

A partir de :

$var=BSD

Nous voulons créer une variable appelée called :

system_BSD

Positionnons à 'yes' la variable 'system_???', où ??? est la valeur de $var :

$ var=BSD
$ system_$var=yes
-bash: system_BSD=yes: command not found

Cela échoue car Bash interprête $var en tant que BSD, puis traite le résultat de 'system_BSD=yes' comme une command. Nous devons évaluer $BSD, puis dire à Bash de ré-analyser la ligne à partir de zéro en utilisant 'eval'.

Pour positionner une variable variable :

$ var=BSD
$ eval "system_$var=yes"
$ echo $system_BSD
yes

Nous voulons afficher la valeur de la même manière :

$ eval "echo $system_$var"
BSD

Nous voulons que $var soit 'eval'uée, mais pas $system:

$ eval "echo \$system_$var"
yes
$

Sousligner une Chaîne

Souslignez une chaîne générique dont la longueur peut être variable.

$ cat ./underline 
#!/bin/bash

read -p 'Entrez une chaîne à sousligner : ' string
len=${#string} echo $string while ((len != 0)); do echo -n "-" ((len = len - 1)) done echo
$ ./underline Entrez une chaîne à sousligner : Ceci est un test. Ceci est un test. ---------------

La construction :

${#var}

retourne la longueur en caractères de 'var'.

Ce petit script utilise les tests et l'arithmétique intégrés d'entiers de Bash :

while ((len != 0)); do
((len = len - 1))

Vous n'avez rien remarqué d'inhabituel ou d'inattendu ?

'echo -n' est utilisé de façon à ne pas faire suivre d'une nouvelle ligne chaque ligne bash .

Cet exemple devrait normalement être codé sous forme de fonction Bash et appelé à chaque fois que le script principal nécessite de sousligner une chaîne.


Retourner des Valeurs Arbitraires

Renvoyer une valeur arbitraire à partir d'une fonction Bash.

Les fonctions Bash renvoyent un statut de sortie compris entre 0 et 255. Cette valeur peut être testée via la variable shell spéciale $?. Mais comment faire pour retourner un nombre arbitraire voire une chaîne ?

Une manière consiste à faire en sorte que la fonction affiche via 'echo' la valeur retournée et d'utiliser la construction $(...) pour capturer la sortie de la fonction. $(...) est en général utilisée pour capturer la sortie des commandes mais elle fonctionne aussi avec les fonctions.

Ici, j'ai converti l'exemple de Lundi en une fonction qui renvoit la chaîne souslignée.

$ cat ./underline 
#!/bin/bash

# Function sousligner # # Génére une chaîne souslignée # # $1: la chaîne à sousligner # $2: le caractère optionnel de souslignement, la valeur par défaut étant '-' # # retour : la chaîne souslignée # underline () { local -i len # pour gérer la longueur de la chaîne placée dans $1 local line # pour gérer la chaîne souslignée générée local char=${2:-"-"} # place le caractère de souslignement dans $2 ou la valeur par défaut s'il n'est pas fourni
len=${#1} while ((len != 0)); do line=${line}$char ((len = len - 1)) done
echo $line }

# Main script # read -p 'Saisir une chaîne à sousligner : ' string echo $string dashes=$(underline "$string") echo $dashes

$ ./underline Saisir une chaîne à sousligner : Ceci est un test... Ceci est un test... -----------------

La fonction 'sousligner' renvoie sa valeur avec :

echo $line

et cette valeur est capturée dans 'dashes' par le script principal en utilisant :

dashes=$(underline "$string")

Ceci est une construction utille :

char=${2:-"-"}

Renvoyer plusieurs valeurs avec un tableau.

Voici un exemple simple qui utilise un tableau pour recevoir plusieurs valeurs d'une fonction. 'count' renvoie quatre chaînes.

$ cat numbers
#!/bin/bash

# Function count # count () { #renvoie one two three four echo one two three four }

# Main # declare -a numbers
numbers=($(count))
echo ${numbers[0]} echo ${numbers[1]} echo ${numbers[2]} echo ${numbers[3]}
$ ./numbers one two three four

Arrêter d'Afficher les Mots de Passe

Empêcher la saisie d'être affichée lorsqu'un script lit un mot de passe.

Un script peut afficher une invite et lire du texte saisi par l'utilisateur mais le texte est affiché. Si un mot de passe est lu, il serait bien d'empêcher qu'il ne s'affiche.

Le secret consiste à utiliser :

stty -echo

pour arrêter l'affichage.

$ cat getpass
#!/bin/bash

read -p "Give your name: " name
stty -echo
read -p "And your password: " pass; echo
stty echo
read -p "And your shoe size: " ss

$ ./getpass
Give your name: Adrian
And your password:
And your shoe size: 9

Accéder au Dernier Paramètre

Obtenir la valeur du dernier paramètre passé à un script/fonction lorsque le nombre de paramètres n'est *pas* connu.

$2 identifie le second paramètre, mais comment obtenir le nième paramètre sans connaître 'n' ?

Le nombre de paramètres est donné par le caractère spécial $#. Nous avons donc besoin de '$$#'.

Aucune de ces tentatives ne fonctionnent :

$ cat lastp
#!/bin/bash
echo $#
echo $$#
echo ${$#}
echo \${$#}


$ ./lastp one two three
3
2428#
2428
${3}

Le secret consiste à évaluer {S#} en premier, puis à évaluer $-le-résultat-de-la-première-évaluation. La fonction eval de Bash fait extactement cela, laissant Bash analyser la ligne deux fois.

$ cat ./lastp
#!/bin/bash

eval echo \$$#

eval last=\$$#
echo $last

$ ./lastp one two three four
four
four

La première analyse effectuée par eval change \$ en $ et $# en 4, résultant en $4. La ligne qui en résulte est alors analysée normalement et elle affiche $4 (ou assige $4 à 'last').


Changer le Globbing Nul du Shell

Changer le comportement du shell dans le globbing.

Normalement, si le globbing (analyse des caractères joker) résulte en rien, le shell renvoie le glob au lieu de nul. Ce n'est pas toujours ce qui est requis dans un script shell.

Par exemple, *.txt est développé en deux fichiers :

$ for file in *.txt; do echo -n $file ": "; head $file; done
f.txt : Hello
g.txt : there

mais *.text ne donne rien :

$ for file in *.text; do echo -n $file ": "; head $file; done
*.text : head: *.text: No such file or directory

Nous aurions préféré que la boucle soit silencieuse au lieu de donner un message d'erreur. Cela peut êtrte effectué en positionnant l'option 'nullglob' de Bash :

$ shopt -s nullglob
$ for file in *.text; do echo -n $file ": "; head $file; done
$

(pas de message d'erreur)

A la fin du script, le comportement par défaut peut être restauré.

$ shopt -u nullglob
$ for file in *.text; do echo -n $file ": "; head $file; done
*.text : head: *.text: No such file or directory
$

Activer FTP

Les astuces de cette semaine montrent comment régler un service FTP simple et complet avec les classes 'chrooting' et d'accès. Note : lire toutes les astuces de cette semaine avant d'exposer votre FTP à Internet.

Activer FTP via l'interface graphique. Dans les Préférences Système sélectionner Partage, l'onglet Services, et vérifier 'Accès FTP'. Le coupe-feu sera automatiquement ouvert.

Activer FTP en ligne de commande.

1) Ouvrez les ports 20 et 21 du coupe-feu et tous les ports hautement numérotés connectés à partir des clients FTP (à partir des ports source 20, 21).

$ sudo ipfw add 03000 allow tcp from any to any 20-21 in
$ sudo ipfw add 03010 allow tcp from any 20,21 to any 1024-65535 in
$ sudo ipfw list
...
03000 allow tcp from any to any 20-21 in
03010 allow tcp from any 20,21 to any 1024-65535 in
...

Les règles 3000 et suivantes ne sont pas utilisées par les réglages par défaut du coupe-feu d'OS X. Vous devrez d'abord utiliser 'ipfw list' pour vérifier cela d'abord si vous utilisez des réglages non-standards.

Note : Les Préférences Système ne vont pas apprécier de voir que vous avez joué avec ses règles de coupe-feu. Si vous voulez que les Préférences retombent sur leurs pieds, faites ceci :

$ sudo ipfw flush
Are you sure? [yn] y

Flushed all rules.

(re-)Lancez les Préférences Systèmes pour activer le coupe-feu.

Pour démarrer FTP éditez le service 'ftp' dans xinet.d. (FTP est réglé comme un service à la demande lancé par xinet.d, par comme un démon permanent.)

$ sudo pico /etc/xinetd.d/ftp

Positionnez le ligne 'disable' sur 'no'

disable = no

Relancez xinet.d pour qu'il lise le fichier modifié (bash) :

$ sudo kill -HUP $(cat /var/run/xinetd.pid)

ou (tcsh, bash) :

$ sudo kill -HUP `cat /var/run/xinetd.pid`

Testez en vous connectant avec 'ftp user@hostname/IP-address':

$ ftp saruman@carcharoth
Connected to carcharoth.mayo-family.com.
220 carcharoth.mayo-family.com FTP server (tnftpd 20040810) ready.
331 Password required for saruman.
Password:
230-
Welcome to Darwin!
230 User saruman logged in.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>...
ftp> quit
221-
Data traffic for this session was 0 bytes in 0 files.
Total traffic for this session was 480 bytes in 0 transfers.
221 Thank you for using the FTP service on carcharoth.mayo-family.com.

Autoriser et Refuser Explicitement

Refuser les accès FTP par défaut.

La configuration standard fournie par Apple autorise tous les utilisateurs à utiliser FTP, sauf ceux explicitement listés - en d'autres termes, accorder par défaut et refuser explicitement. Un réglage plus sécurisé consisterait à refuser par défaut et à autoriser ecplicitement.

Changez le fichier /etc/ftpusers :

$ cat /etc/ftpusers
# list of users disallowed any ftp access.
# read by ftpd(8).
Administrator
administrator
root
uucp
daemon
unknown
www

en :

$ cat /etc/ftpusers
# list of users allowed ftp access.
# read by ftpd(8).
saruman allow
loraine allow
... list all the accounts that may ftp...

# deny all other users
* deny

ce fichier doit être effacé par root ou via 'sudo'.


Jail et Umask

Emprisonner les utilisateurs dans leur répertoire départ.

La configuration standard fournie par Apple permet à tous les utilisateurs d'avoir le même accès aux fichiers systèmes lorsqu'ils se connectent. Cela veut dire qu'ils peuvent faire 'cd /' et voir plein de fichiers système. Une approche plus sécurisée consisterait à emprisonner les utilisateurs de façon à ce qu'un 'cd /' les emmène dans leur répertoire départ. Pour ces utilisateurs, leur répertoire départ est la racine de leur système de fichiers et ils ne pourront jamais se déplacer à un autre niveau.

Editez / créez le fichier /etc/ftpchroot :

$ sudo pico /etc/ftpchroot

de façon à ce qu'il ressemble à cela :

$ cat /etc/ftpchroot
# all users are chrooted
*

L'astuce de demain montre comment emprisonner certains utilisateurs et pas d'autres (sans explicitement lister les utilisateurs 'chrootés').

Changez le umask par défaut.

Le umask FTP par défaut est 027, en opposition au plus courant 022. Cela veut dire que les utilisateurs qui chargent des fichiers devant être servis par Apache créent des fichiers qui ne pourront pas être lus par Apache.

FTP fournit une commande 'chmod' :

ftp> help chmod
chmod change file permissions of remote file

mais une solution plus commode consisterait à changer le umask par défaut pour tous les utilisateurs en 022..

Editez / créez le fichier /etc/ftpd.conf :

$ sudo pico /etc/ftpd.conf

pour qu'il ressemble à cela :

$ cat /etc/ftpd.conf
# normally 027
umask all 022

Testez avec :

$ ftp loraine@carcharoth
Connected to carcharoth.mayo-family.com.
....
230 User loraine logged in.
ftp> umask
200 Current UMASK is 022
ftp> quit
...
$

Définir les Classes d'Utilisateurs

Pouor contrôler les accès FTP, les réglages umask, le 'chrootage' (de 'chroot', changer le répertoire racine), etc, FTP permet de définir des classes. Les réglages peuvent être définis pour une classe et chaque utilisateur peut être assigné à une classe appropriée. Un utilisateur héritera alors des attributs de la classe à laquelle il appartient.

Editez le fichier de configuration de ftp pour définir les classes.

$ sudo pico /etc/ftpd.conf

Dans la configuration qui suit, j'ai défini deux classes : 'libre' et 'restreinte'. J'ai changé le répertoire racine en '/' de façon à ce qu'ils peuvent voir le système en entier (réglage par défaut). Les utilisateurs 'restreints' ne peuvent voir que leur répertoire départ (%d). Notez que 'homedir' est positionné sur '/' pour les utilisateurs restreints, ce qui représente leur répertoire départ compte tenu du réglage appliqué à leur 'chroot'.

$ cat /etc/ftpd.conf

# les utilisateurs de la classe 'libre' (voir /etc/ftpusers) sont 'chrootés' vers /
# avec leur répertoire départ ftp positionnés sur celui de leur connexion
chroot libre /
homedir libre %d

# les utilisateurs de la classe 'restreinte' (voir /etc/ftpusers) sont 'chrootés'
# vers leur répertoire départ, leur répertoire de départ ftp est positionné sur
# leur nouvelle racine (càd leur répertoire départ de connexion)
chroot restreinte %d
homedir restreinte /

# change le umask de sa valeur par défaut 027
umask all 022

La dernière directive régle le umask pour 'all' (tous), ce qui représente toutes les classes.


Sécurité

FTP n'est le plus sécurisé des services. Un réglage précautionneux est une bonne chose, mais souvenez vous que les mots de passe et toutes les communications sont transmises de manière non encryptée.

Si vous lancez ssh (Secure SHell) vous pourrez alors tirer partie des copies sécurisées et du FTP sécurisé. Vous devez déjà avoir ssh de réglé pour utiliser ces services.

scp se comporte comme la copie normale d'Unix, mais elle copie au travers de réseau en utilisant un accès ssh. Pour copier le fichier 'test' dans mon répertoire départ sur l'hôte saruman.wless, je peux utiliser :

$ scp ~/test saruman.wless:~/test

Pour utiliser scp, précédez le chemin d'accès à la machine distante de 'hostname:' ou de 'ip-address:'.

L'équivalent de 'ftp' est 'sftp'. De ce que j'en sais, il n'est pas possible de configurer sftp au même niveau que ftp. Par exemple, il n'est pas possible d'emprisonner les utilisateurs dans leur répertoire départ.

Notez : Pour utiliser scp, assurez vous que le fichier /etc/sshd_config comporte la ligne :

# Annule le réglage par défaut des non sous-systèmes
Subsystem sftp /usr/libexec/sftp-server

Enfin, pour restreindre le nombre de ports sur lequel un client pour se connecter, utiliser (par exemple) :

# Régler la rangée de ports pour les accès passifs de toutes les classes
portrange all 40000 40999

Le réglage par défaut est 1024-65535. Après avoir effectué ce changement, vous pouvez alors restreindre le nombre de ports ouverts dans le coupe-feu ainsi :

03010 allow tcp from any 20,21 to any 40000-40999 in

Strings et Vis

Utilisez 'strings' pour retirer des caractères indésirables.

La commande strings recherche dans un fichier les chaînes imprimables et les affiche. Elle peut être utilisée sur un fichier texte pour retirer les caractères artificiels non imprimables.

$ strings text-file > text-file.clean

Jetez un coup d'oeil à l'intérieure des commandes.

Utilisez strings sur des commandes telles que 'ls' pour découvrir du texte incorporé :

$ strings /bin/ls
__dyld_mod_term_funcs
__dyld_make_delayed_module_initializer_calls
The kernel support for the dynamic linker is not present to run this program.
$FreeBSD: src/bin/ls/cmp.c,v 1.12 2002/06/30 05:13:54 obrien Exp $
@(#) Copyright (c) 1989, 1993, 1994
The Regents of the University of California. All rights reserved.
$FreeBSD: src/bin/ls/ls.c,v 1.66 2002/09/21 01:28:36 wollman Exp $
COLUMNS
CLICOLOR
1ABCFGHLPRSTWZabcdfghiklmnopqrstuvwx
...

Utilisez 'vis' pour afficher des fichiers impropres.

Vis affiche les caractères de contrôle tels que les séquences d'échappement, vous permettant ainsi de voir le contenu de fichiers qui, autrement, balancerait des saletés sur le terminal.


File et Hexdump

Utilisez 'file' pour décourvrir les types de fichiers.

$ file safari-bm.html
safari-bm.html: iso-8859-15 Unicode English text, with very long lines

$ file safari-bm.txt
safari-bm.txt: OS/2 URL object text (WWW)
http://album>

$ file /bin/ls
/bin/ls: Mach-O executable ppc

$ file /
/: sticky directory

$ file ~
/Users/saruman: directory

$ file /dev/disk0
/dev/disk0: block special (14/0)

$ file /dev/rdisk0
/dev/rdisk0: character special (14/0)

et ainsi de suite...

Utilisez 'hexdump' pour afficher le contenu d'un fichier en héxadécimale.

$ hexdump /bin/ls | head -n 5
0000000 feed face 0000 0012 0000 0000 0000 0002
0000010 0000 000f 0000 0778 0000 0095 0000 0001
0000020 0000 0038 5f5f 5041 4745 5a45 524f 0000
0000030 0000 0000 0000 0000 0000 1000 0000 0000
0000040 0000 0000 0000 0000 0000 0000 0000 0000

hexdump est utile pour révéler les caractères de contrôle dans un fichier texte ou pour examiner le contenu d'un fichier binaire.

Notez que les exécutables Mach-O commencent avec la séquence héxa 'feed face' :-)


A quelle heure la pause ?

Utilisez 'leave' de façon à ne plus jamais oublier d'aller déjeuner.

Déjeuner à 13h00 :

$ leave 0100
Alarm set for Mon Dec 27 13:00. (pid 10494)

Café dans 10 minutes :

$ leave +10
Alarm set for Mon Dec 27 12:38. (pid 10497)

Leave vous rappellera périodiquement l'évènement à venir et de plus en plus fréquemment à l'arrivée de l'évènement.

$ You have to leave in 5 minutes.
($ Vous devrez arrêter dans 5 minutes.)
...
$ Just one more minute!
($ Plus qu'une minute !)
...
Time to leave!
(Il est temps d'arrêter !)
...
Time to leave!
(Il est temps d'arrêter !)
...
Time to leave!
(Il est temps d'arrêter !)
...

Lorsque vous vous déconnectez, le harcèlement s'arrête. Si vous ne vous déconnectez pas, interrompez 'leave' avec la commande kill en utilisant le pid tel qu'il a été affiché au moment de mettre en place le rappel.

$ kill -KILL 10494

Pour tuer tous les 'leaves', utilisez :

$ kill -KILL $(ps | grep ' [l]eave ' | awk '{print $1}')

(sous tcsh utilisez :)

$ kill -KILL `ps | grep ' [l]eave ' | awk '{print $1}'`

Voir aussi la semaine 41 : commande 'at' et commande 'calendar'.


Enregistrez une Session Terminal

Utilisez 'script' pour enregistrer une séquence de commandes.

Si vous êtes en train de faire quelque chose que vous pourriez avoir à répéter plus tard ou dont vous souhaiteriez que les autres profitent, utilisez la commande script pour enregistrer une session terminal dans un fichier (~/typescript si aucun fichier n'est donné). L'option -a ajoute la séquence à un fichier script existant.

$ script
Script started, output file is typescript
$ cd ~
$ ls
Desktop Documents Movies Pictures Sites osxfaq test.clean
Development Library Music Public bin test typescript
$ rm test
$ rm test.clean
(à cet endroit, pressez control-D pour arrêter la session script)
$ exit
Script done, output file is typescript

Observez le fichier script :

$ cat ~/typescript
Script started on Mon Dec 27 12:45:12 2004
$ cd ~
$ ls
Desktop Documents Movies Pictures Sites osxfaq test.clean
Development Library Music Public bin test typescript
$ rm test
$ rm test.clean
$ exit

Script done on Mon Dec 27 12:45:34 2004
$

Bien entendu, si vous ne souhaitez rappeler que les commandes que vous avez tapées, utilisez l'historique.

$ history -c
$ cd ~
$ ls
Desktop Documents Movies Pictures Sites osxfaq .....

Mettez fin à la session

$ history > ~/what-i-typed

Qui est là ?

Il y a plusieurs commandes permettant de savoir quels utilisateurs sont actuellement connectés sur votre Mac ou votre serveur.

$ who
saruman console Dec 19 17:29
ferdi ttyp2 Dec 23 21:30 (10.0.2.1)

L'utilisateur 'ferdi' est connecté à partir d'une autre machine tel qu'indiqué par l'adresse IP entre parenthèses. Vous pouvez envoyer un message à cet utilisateur directement sur sa console :

$ write ferdi [ttyp2]
get off

Le numéro de tty est optionnel s'il est n'est connecté qu'une seule fois.

La commande 'w' donne un peu plus d'informations.

$ w
21:30 up 6 days, 2:36, 2 users, load averages: 0.45 0.21 0.21
USER TTY FROM LOGIN@ IDLE WHAT
saruman console - Sun17 4days -
ferdi p2 middle-earth.wle 21:30 - -bash

La commande 'users' ne liste que les utilisateurs locaux :

$ users
saruman

La commande 'last' donne un historique de qui a été et de qui est toujours connecté :

$ last | head -n 5
ferdi ttyp2 10.0.2.1 Thu Dec 23 21:30 still logged in
saruman ttyp2 10.0.2.1 Thu Dec 23 21:25 - 21:26 (00:00)
saruman ttyp2 10.0.2.1 Thu Dec 23 21:19 - 21:25 (00:05)
saruman ttyp3 Thu Dec 23 21:01 still logged in
saruman ttyp3 Thu Dec 23 21:01 - 21:01 (00:00)

'uptime' permet de savoir combien de temps votre serveur a été actif.

$ uptime
21:16 up 6 days, 2:22, 2 users, load averages: 0.21 0.36 0.28

Commandes Service de Répertoire

Cette semaine est la suite de la semaine 91 avec des scripts encore plus utiles pour gérer les comptes utilisateurs en ligne de commande - supprimer un groupe, supprimer un utilisateur dans un groupe et supprimer un utilisateur.

Tout d'abord, voici quelques astuces sur les commandes permettant de requérir le compte d'un utilisateur dans NetInfo.

Utilisez 'dcsl list' pour afficher les groupes et les utilisateurs.

$ dscl . list /groups
admin
appserveradm
appserverusr
bin
claire
...

$ dscl . list /users
appserver
claire
cyrus
daemon
...

Utilisez 'dscl search' pour vérifier les paires propriété-valeur.

$ dscl . search  /groups name claire
Search results for dsAttrTypeStandard:name
Search results for dsAttrTypeNative:name
claire          dsAttrTypeNative:name = (claire)

Utilisez 'dscl read' pour afficher les propriétés et les valeurs.

$ dscl . read /groups
name: dsRecTypeNative:groups

$ dscl . read /groups/claire
AppleMetaNodeLocation: /NetInfo/DefaultLocalNode
GeneratedUID: 0066A0DA-ED62-11D8-B80E-000393B2D604
GroupMembership:
Password: *
PrimaryGroupID: 507
RecordName: claire

Utilisez 'nifind' pour vérifier qu'une entrée (groupe, utilisateur, etc) existe.

$ nifind /users/claire .
/users/claire found in ., id = 90

$ nifind /users/xxxxxxxxx .
$

Supprimer un Groupe

Utilisez ce script pour supprimer un groupe de NetInfo.

Le script peut être récupéré ici.

$ cat del-group
#!/bin/bash

# Supprimer un groupe. # Prend en entrée le nom du groupe et le supprimer de NetInfo
declare quiet="no" # -q option non spécifiée declare group # suppporte le nom du groupe declare gid # supporte l'id du groupe déduit du nom declare ans # réponse
usage () { echo "Supprimer un groupe" echo "Utilisation : ${0##*/} [-q] nomdugroupe" echo " -q - quiet: pas d'avertissement ou de demande de confirmation" echo " sinon un avertissement est affiché si le groupe à supprimer" echo " est un groupe primaire" if [ "$*" != "" ]; then echo; echo "Erreur : $*"; fi exit 1 }

# Ce script doit être lancé par root # if [ "$USER" != "root" ]; then echo "Ce script doit être lancé par root" exit 1 fi

# Vérification des paramètres # if [ "$1" = "-q" ]; then quiet="yes" shift fi
if [ $# -ne 1 ]; then usage fi
group="$1"
# cherche le groupe dans NetInfo - il doit exister str="$(nifind /groups/$group .)" if [ -z "$str" ]; then usage "Le Groupe $group n'existe pas" fi

# Vérifie que le groupe n'est pas un groupe primaire et affiche un avertissement # mais pas en mode quiet if [ $quiet = "no" ]; then
# récupère le n° du groupe gid="$(nireport . /groups name gid | grep -w "^$group" | cut -f 2)"
# affiche un avertissement si c'est un groupe primaire str="$(nireport . /users gid | grep -w $gid)" if [ ! -z "$str" ]; then echo "ATTENTION : Le groupe est un groupe primaire :" nireport . /users gid name | grep -w "^$gid"
read -p "Tapez a pour stopper le script : " ans if [ "$ans" = "a" ]; then echo "Aborted" exit fi fi fi

# Supprime le groupe de NetInfo # # sanity check if [ "$group" = "" ]; then exit; fi
dscl . delete /groups/$group
echo "Le Groupe $group a été supprimé" exit 0

Supprimer un Utilisateur dans un Groupe

Utilisez ce script pour supprimer un utilisateur dans un groupe ou dans tous les groupes.

Récupérez le script ici.

$ cat del-user4group

#!/bin/bash
# Supprime un utilisateur dans un groupe ou dans tous les groupes # Supprime un utilisateur existant dans un groupe existant de NetInfo, ou # dans tous les groupes auquel l'utilisateur appartient (mais dans le groupe primaire)
declare groups # supporte le nom du groupe ou la liste des groupes declare user # supporte le nom du compte utilisateur declare gid # supporte l'id du groupe déduit du nom du groupe declare str strgroup stringroup strprimary # working

usage () { echo "Supprimer un utilisateur dans un groupe ou dans tous les groupes" echo "Utilisation : ${0##*/} group|all user" echo " avec 'all', l'utilisateur est supprimé de tous les groupes sauf le groupe primaire" if [ "$*" != "" ]; then echo; echo "Erreur : $*"; fi exit 1 }

# On vérifie que l'utilisateur est root # if [ "$USER" != "root" ]; then echo "Le script doit être lancé par root" exit 1 fi

# Vérification des paramètres # if [ $# -lt 2 ]; then usage fi
groups="$1"; user="$2"
# Si le groupe est all, on remplace par la liste des groupes auxquels l'utilisateur appartient # if [ $groups = "all" ]; then groups="$(id -Gnr $user)" fi
# Boucle pour supprimer l'utilisateur de chaque groupe # for group in $groups; do
# récupère l'id du groupe gid="$(nireport . /groups name gid | grep -w "^$group" | cut -f 2)"
# vérifie que le groupe existe strgroup="$(nifind /groups/$group .)" # vérifie que l'utilisateur appartient au groupe stringroup="$(nireport . /groups name users | grep -w "^$group[[:space:]].*$user")" # vérifie que le groupe n'est pas le groupe primaire strprimary="$(nireport . /users name gid | grep -w "^$user[[:space:]]*$gid")"
# s'assure que le groupe existe... if [ -z "$strgroup" ]; then echo "Le Groupe $group n'existe pas" # ...et que ce n'est pas le groupe primaire elif [ ! -z "$strprimary" ]; then echo "Aucune suppression dans le groupe primaire $group" # ...et que l'utilisateur appartient au groupe elif [ -z "$stringroup" ]; then echo "L'utilisateur $user n'est pas listé dans $group" else # supprime l'utilisateur du groupe
dscl . delete /groups/$group users $user echo "Utilisateur $user supprimé du groupe $group" fi done
exit 0

Supprimer un Utilisateur

Utilisez ce script pour supprimer un utilisateur.

L'utilisateur et son groupe primaire sont supprimés. L'utilisateur est retiré de tous les autres groupes. Le dossier départ de l'utilisateur est archivé puis supprimé.

Il utilise les deux scripts précédents.

Récupérez le script ici.

$cat del-user

#!/bin/bash
# Delete a user. # Takes the account name (short name) and: # removes the user from all groups # removes the user's primary group (of the same name) # removes the user's account in NetInfo # archives and deletes the user's home directory in /Users/shortname
declare user # to hold user's account name declare str # working

usage () { echo "Delete a user account, group, and group membership" echo "Usage: ${0##*/} username" if [ "$*" != "" ]; then echo; echo "Error: $*"; fi exit 1 }

# The script must be run as root # if [ "$USER" != "root" ]; then echo "Must be run as root" exit 1 fi

# Check parameters # if [ $# -ne 1 ]; then usage fi
user="$1"
# search NetInfo for the given user - it should exist str="$(nifind /users/$user .)" if [ -z "$str" ]; then usage "User $user does not exist" fi
# Delete the user from NetInfo # # delete the user from all groups del-user4group all $user
# delete the user's primary group del-group -q $user
# delete the user from NetInfo dscl . delete /users/$user
echo "User $user deleted"
# Archive the user's home directory # # check that the user has a home directory if [ -e /Users/$user ]; then # archive it cd /Users tar -czf ${user}-archive.tgz $user cd -
# delete it CHECKING THAT AN ARCHIVE WAS CRESATED if [ -e /Users/${user}-archive.tgz ]; then rm -rf /Users/${user}/ fi fi
echo "User's home directory archived and deleted"
exit 0

Changer d'Emplacement Réseau

Changer d'emplacement réseau à partir de la ligne de commande.

La commande :

$ scselect

liste tous les emplacements réseau, comme c'est le cas dans les Préférences Systèmes:: Réseau.

La commande :

$ scselect location-name

change l'emplacement réseau actuel et sélectionne le nouveau.


Nouveau Depuis

(Voi aussi les semaines &, 13, 31 et 49)

Listez tous les fichiers créés depuis le dernier démarrage :

$ find ~ -newer /mach.sym

Cela permet de trouver tous les fichiers de votre dossier départ qui sont plus récents que /mach.sym. /mach.sym est un des fichiers qu'OS X génère au démarrage.

Créez un fichier en début de journée pour garder trace de tous les fichiers que vous avez créés ou modifiés durant cette journée.

$ touch ~/marker

et plus tard...

$ find ~ -newer ~/marker

D'autres exemples.

Trouvez tous les répertoires nouveaux ou modifiés, mais avec une profondeur limitée à 2 sous-répertoires.

$ find ~ -newer /mach.sym -type d -maxdepth 2

'-type' peut aussi être 'f' pour fichier, 'l' pour lien symbolique ou d'autres types de fichiers spéciaux - se reporter à 'man find'.

Trouvez tous les nouveaux fichiers de taille supérieure à 1MB. '-size' est spécifié en blocs de 512 octets ou en moitié de K. '-ls' liste les détails de chaque fichier.

$ find ~ -newer /mach.sym -size +2000 -ls

'-size' peut s'appliquer à une taille précise en nombre de blocs si l'on omet le signe '+', ou à une taille inférieure à celle spécifiée si l'on précise le signe '-'. Ex : -size -2000 pour moins d' 1MB.


Conditions Complexes

Utilisez des critères de sélection complexes avec 'and' et 'or'.

Remarquez les dates de modification et les tailles des fichiers suivants :

$ ls -l
total 49M
... 15M Jan 15 12:12 ferdi-coll3.psd
... 30M Jan 23 11:59 ferdi-cool.psd
... 1.7M Jan 15 12:12 ferdi-gala.psd
... 1.6M Jan 23 15:59 ferdi-polish.psd

Trouvez les fichiers modifiés moins d'1 jour auparavant :

$ find . -mtime -1
.
./ferdi-cool.psd
./ferdi-polish.psd

Trouvez les fichiers modifiés plus d'1 jour auparavant :

$ find . -mtime +1
./ferdi-coll3.psd
./ferdi-gala.psd

Trouvez les fichiers de taille inférieure à 5M :

$ find . -size -10000
.
./ferdi-gala.psd
./ferdi-polish.psd

Trouvez les fichiers de taille supérieure à 5M :

$ find . -size +10000
./ferdi-coll3.psd
./ferdi-cool.psd

Trouvez les fichiers de taille supérieure à 5M ET modifiés moins d'1 jour auparavant :

$ find . -mtime -1 -a -size +10000
./ferdi-cool.psd

Trouvez les fichiers de taille inférieure à 5M ET modifiés plus d'1 jour auparavant :

$ find . -mtime +1 -a -size -10000
./ferdi-gala.psd

Trouvez les fichiers
modifiés moins d'un jour auparavant ET de taille supérieure à 5M
OU
modifiés plus d'un jour auparavant ET de taille inférieure à 5M :

$ find . \( -mtime -1 -a -size +10000 \) -o \( -mtime +1 -a -size -10000 \)
./ferdi-cool.psd
./ferdi-gala.psd

Remarquez l'utilisation des parenthèses (échappées du shell) pour être sûr que les expression AND et OR soient évaluées dans l'ordre correct - c'est à dire, les deux AND d'abord puis le OR.

Du fait que 'find' suppose le AND par défaut, l'expression dans ce cas peut être raccourcie à :

$ find . \( -mtime -1 -size +10000 \) -o \( -mtime +1 -size -10000 \)
./ferdi-cool.psd
./ferdi-gala.psd

Aussi, du fait que 'find' évalue AND avant OR, les parenthèses peuvent être omises.

$ find . -mtime -1 -size +10000 -o -mtime +1 -size -10000
./ferdi-cool.psd
./ferdi-gala.psd

Si l'expression avait été de la forme :
(a -o b) -a (c -o d)
les parenthèses auraient été nécessaires.


Restreindre le Find

Empêcher le 'find' de traverser d'autres systèmes de fichiers et de suivre des liens symboliques.

Utilisez l'option '-x' pour empêcher 'find' de regarder à l'intérieur des volumes montés :

$ ls /Volumes/
Inside Mac Media OSX-saruman guest

$ find -x /Volumes
/Volumes
/Volumes/guest
/Volumes/Inside Mac Media
/Volumes/OSX-saruman

Seul /Volumes sera examiné, les trois autres volumes montés ne le seront pas. Comparez en lançant cette commande sans l'option '-x'.

Find non récursif.

$ find * -prune -size +10 -ls

Cette commande cherche tous les fichiers du répertoire courant dont la taille est supérieure à 5K et liste leurs détails avec '-ls'. '-prune' empêche find de rechercher de manière récursive dans chaque répertoire.

Remarquez que :

$ find . -prune -size +10 -ls

ne marchera pas parce que 'find' ne fera pas de recherche récursive dans le répertoire spécifié '.'.

Cela marchera :

$ find . -maxdepth 1 -size +10 -ls

Faites en sorte que 'find' suive les liens symboliques.

Find ne suit pas les liens symboliques par défaut - 'home' dans cet exemple.

$ ls -l
total 49700
... Jan 15 12:12 ferdi-coll3.psd
... Jan 23 11:59 ferdi-cool.psd
... Jan 15 12:12 ferdi-gala.psd
... Jan 23 15:59 ferdi-polish.psd
... Jan 23 16:46 home -> /Users/saruman $ find . -name "*.psd"
./ferdi-coll3.psd
./ferdi-cool.psd
./ferdi-gala.psd
./ferdi-polish.psd

Utilisez l'option -L pour indiquer à 'find' de suivre les liens symboliques :

$ find -L . -name "*.psd"
./ferdi-coll3.psd
./ferdi-cool.psd
./ferdi-gala.psd
./ferdi-polish.psd
./home/Pictures/complete/ferdi-coll3.psd
./home/Pictures/complete/ferdi-cool.psd
./home/Pictures/complete/ferdi-gala.psd
./home/Pictures/complete/ferdi-polish.psd
...

L'option '-H' dit à 'find' de suivre le lien symbolique spécifié sur la ligne de commande plutôt que ceux trouvés durant la recherche.

Cela ne suivra pas 'home' :

$ find -H . -name "*.psd"

Par contre, cela le fera :

$ find -H * -name "*.psd"

Find et Du

Trouvez le top ten des fichiers/répertoires les plus grands.

$ du -sk ~/* | sort -nr | head -n 10
2252708 /Users/saruman/Pictures
490664 /Users/saruman/Library
186164 /Users/saruman/Sites
132596 /Users/saruman/Development
46928 /Users/saruman/Documents
33216 /Users/saruman/osxfaq
14372 /Users/saruman/Movies
12304 /Users/saruman/.Trash
10252 /Users/saruman/Desktop
580 /Users/saruman/.gimp-2.0

'du' (Disk Usage) affiche la taille de tous les fichiers/répertoires (~/*). '-s' réduit l'affichage à juste la taille totale des répertoires, 'sort -nr' trie numériquement de manière inverses (du plus grand au plus petit) et 'head -n 10' n'affiche que les 10 premières lignes.

Améliorez ce 'find' pour n'inclure que les répertoires.

$ find ~ -type d -maxdepth 1 -print0 | xargs -0 du -sk | sort -nr | head -n 10
3181012 /Users/saruman
2252708 /Users/saruman/Pictures
490664 /Users/saruman/Library
186164 /Users/saruman/Sites
132596 /Users/saruman/Development
46928 /Users/saruman/Documents
33216 /Users/saruman/osxfaq
14372 /Users/saruman/Movies
12304 /Users/saruman/.Trash
10252 /Users/saruman/Desktop

(les options '-print0' et '-0' s'adressent aux noms de fichier comprenant des espaces - voir les pages man)

Augmentez la profondeur.

$ find ~ -type d -maxdepth 2 -print0 | xargs -0 /usr/bin/du -sk | sort -nr | head -n 20
3181012 /Users/saruman
2252708 /Users/saruman/Pictures
1772768 /Users/saruman/Pictures/iPhoto Library
490664 /Users/saruman/Library
378168 /Users/saruman/Library/Caches
308072 /Users/saruman/Pictures/complete
186164 /Users/saruman/Sites
142848 /Users/saruman/Sites/albums
132596 /Users/saruman/Development
80224 /Users/saruman/Development/developer-downloads
77160 /Users/saruman/Pictures/people
69472 /Users/saruman/Library/Mail
54920 /Users/saruman/Pictures/web-site
50224 /Users/saruman/Development/test
46928 /Users/saruman/Documents
33216 /Users/saruman/osxfaq
26304 /Users/saruman/Pictures/Photoshop-effects
20076 /Users/saruman/Library/Application Support
19100 /Users/saruman/Documents/1dot1
19012 /Users/saruman/osxfaq/sf03

Trouver son Chemin

Utilisez '-regex' pour traverser un chemin en entier.

Les semaines précédentes ont abordé '-name' et '-iname' qui ne s'appliquaient qu'au noms des fichiers. '-regex' s'applique au chemin entier.

Trouvez tous les répertoires appelés test, où qu'ils soient dans la hiérarchie des répertoires.

$ find ~ -regex ".*/test/.*"

trouvera :

/Users/saruman/Development/test/*

et

/Users/saruman/Pictures/Gimp/test/*

En plus, l'option '-E' indique d'utiliser des expression régulières et '-iregex' indique qu'elle doit s'appliquer de manière non sensible à la casse.

Retirez facilement le nom complet du chemin d'accès.

$ find ~ -name "*.psd" -execdir echo {} ;
ferdi-coll3.psd
ferdi-cool.psd
ferdi-gala.psd
ferdi-polish.psd

par opposition à la forme classique :

$ find ~ -name "*.psd"
/Users/saruman/Development/test/find/ferdi-coll3.psd
/Users/saruman/Development/test/find/ferdi-cool.psd
/Users/saruman/Development/test/find/ferdi-gala.psd
/Users/saruman/Development/test/find/ferdi-polish.psd
...

Sur la Ligne de Commande

La copie avec des noms de fichier contenant des espaces est problématique à la fois pour celui qui débute avec les lignes de commandes et pour celui qui est plus expérimenté. Cette semaine apporte quelques solutions.

Espaces dans les Noms de Fichier. Pour saisir sur la ligne de commande un nom de fichier qui contient des espaces, utilisez :

my file
"my file"

ou

'my file'

Autrement, tapez la première partie du nom de fichier et pressez la touche tab pour le compléter automatiquement.

L'échappement peut aussi être utilisé pour désigner un nom de fichier qui comprend des caractères bizarres tels que " ou .

$ ls a*
a"b ab

$ cat a'"'b
double quote in name
$ cat a"b
double quote in name
$ cat a''b
back-slash in name
$ cat ab
back-slash in name

Find, Xargs et Espaces

'Find' est une commande souvent utilisée pour dénicher des fichiers particuliers dans une hiérarchie de répertoires et pour traiter chaque fichier, en passant souvent les noms de fichier à 'xargs'.

Cependant, cela échouera pour les noms de fichier contenant des espaces :

$ ls -1 file*
file one
file two

$ find . -name "file*" | xargs ls -l
ls: ./file: No such file or directory
ls: one: No such file or directory
ls: ./file: No such file or directory
ls: two: No such file or directory

Corrigez cela en utilisant l'option '-print0' de 'find', et l'option '-0' de 'xargs'.

$ find . -name "file*" -print0 | xargs -0 ls -l
-rw-r--r--    1 saruman  saruman         0 Feb  7 14:34 ./file one
-rw-r--r--    1 saruman  saruman         0 Feb  7 14:34 ./file two

'-print0' indique à 'find' de séparer les noms de fichier par le caractère 'null' au lieu d'utiliser un espace, lorsqu'il produit la liste des fichiers trouvés. '-0' indique à 'xargs' de s'attendre à des noms de fichiers séparés par 'null'.


Partir en Vrille

Choisissez la correcte méthode de boucle afin de préserver les espaces dans les noms de fichier.

Pour traiter ces deux fichiers :

$ ls -1 file*
file one
file two

Cela ne marchera pas :

$ cat loop
#!/bin/bash
ls=$(ls file*)

for i in $ls; do echo "File: $i" done
$ ./loop File: file File: one File: file File: two

Cela marchera :

$ cat loop
#!/bin/bash

for i in file*; do echo "File: $i" done
$ ./loop File: file one File: file two

Lorsque la recherche est effectuée directement dans la boucle, chaque nom de fichier est traité individuellement, c'est à dire qu'il n'y a pas de confusion entre les espaces contenus dans les noms de fichier et ceux servant à les séparer dans la liste. Lorsque une variable intermédiaire est utilisée, la boucle est alimentée par une liste de noms séparés par des blancs.


IFS de Bash

L'exemple de Mercredi ne peut être utilisé si la liste de noms de fichier est générée par une méthode plus complexe que celle qui consiste à analyser des jokers : par exemple en utilisant 'find.

Cela ne marchera pas :

$ cat ./find-and-loop 
#!/bin/bash 
list=$(find . -atime -1)

for i in $list; do echo "File: $i" done
$ ./find-and-loop File: . File: ./file File: one File: ./file File: two

Ni en utilisant :

for i in $(find . -atime -1); do

Soyez plus ingénieux en utilisant l'Internal File Separator (IFS) de Bash. Normallement, le séparateur est soit un espace, soit une tabulation, soit une nouvelle ligne. 'Find' (et 'ls' ) produit des listes séparées par des nouvelles lignes, donc le simple fait de dire que l'IFS sera une nouvelle ligne fera l'affaire.

$ cat find-and-loop 
#!/bin/bash 

list=$(find . -atime -1 ) IFS=" "
for i in $list; do echo "File: $i" done
$ ./find-and-loop File: . File: ./file one File: ./file two

Remarque : Il n'y a qu'un seul caractère de nouvelle ligne entre les guillemets dans l'expression IFS="

"

Redimensionner et Déplacer avec des Séquences d'Echappement

Redimensionnez et déplacez une fenêtre de terminal à partir de la ligne de commande ou d'un script en utilisant les séquences d'échappement suivantes.

Redimensionnez à un nombre spécifique de lignes et de colonnes (ex : 50 lignes par 100 colonnes) :

$ echo -n "^[[8;50;100t"

(Note : la séquence ^[ représente le caractère escape, obtenu en tapant contrôle-v puis la touche 'esc')

Redimensionnez à la largeur de l'écran en passant un nombre nul de colonnes :

$ echo -n "^[[8;50;0t"

Redimensionnez à la hauteur de l'écran en passant un nombre nul de lignes :

$ echo -n "^[[8;0;100t"

Déplacez à une position donnée (ex : 10 pixels à partir du bord gauche et 100 pixels à partir du bord haut) :

$ echo -n "^[[3;10;100;t"

Lorsque vous redimensionnez à la hauteur et/ou la largeur de l'écran, il est recommandé de positionner la fenêtre en haut à gauche :

$ echo -n "^[[3;0;0;t^[[8;0;0t"

Définir les Alias et les Fonctions

Définir les Alias et les Fonctions pour déplacer et redimensionner. Par exemple, pour avoir un grand écran, utilisez un alias :

(Bash)

$ alias big='echo -n "^[[3;0;0;t^[[8;0;0t"'

(tcsh)

% alias big 'echo -n "^[[3;0;0;t^[[8;0;0t"'

Pour dimensionner un écran, utilisez une fonction Bash ou un alias tcsh :

(Bash)

$ sz ()
> {
> echo -n "^[[8;$1;$2;t"
> }

(tcsh)

alias sz 'echo -n "^[[8;\!:1;\!:2;t"'

Puis utilisez :

$ sz 50 100 $ sz 25 80

Ces séquences d'échappement fonctionnent à la fois pour le terminal d'Apple et pour le xterm X11.


Focus et Dock avec des Séquences d'Echappement

Déplacez une fenêtre à l'arrière-plan ou au premier plan à partir de la ligne de commande ou dans un script en utilisant les séquences d'échappement suivantes. (Voir aussi Lundi)

echo -n "^[[6t;"; sleep 5; echo -n "^[[5t;"

La commande du dessus masque la fenêtre du terminal, fait une pause de 5 secondes puis la remet sous le focus. La partie 'sleep 5' pourrait être un script qui prend un moment pour s'exécuter. Lorsque le script est terminé, la fenêtre du terminal réapparaît pour vous le faire savoir.

(Note : la séquence ^[ représente le caractère escape, obtenu en tapant contrôle-v puis la touche 'esc')

Placez une fenêtre dans le Dock.

$ echo -n "^[[2t;"; sleep 5; echo -n "^[[5t;"

La commande du dessus met la fenêtre dans le dock puis après 5 secondes la remet sous le focus.

Ces séquences peuvent être placées dans un alias bash/tcsh - voir l'astuce de Mardi.


Fonctions Sympas de Terminal.app

Le Terminal d'Apple possède quelques fonctions sympas que vous avez pu peut-être rencontrer.

Scinder la fenêtre. Cliquez sur la petite icône 'scinder' située en haut à droite au dessus de la barre verticale de défilement, puis déplacez la barre horizontale pour ajuster la dimension des deux aires ainsi créées. La partie du haut peut être utilisée comme panneau de visualisation des commandes précédentes sans déranger la fenêtre principale.

Glisser Déposer. Déposer toute sorte de fichier ou de dossier (ou plusieurs) sur la fenêtre du terminal et le chemin d'accès complet sera inscrit derrière l'invite de commande. Par exemple, pour lister le contenu d'un dossier, tapez 'ls' puis déposez le dossier à partir du Finder sur la fenêtre du Terminal et tapez Retour.

Régler un fond d'écran. La plupart des aspects visuels du Terminal peuvent être changés à partir du Terminal -> Réglages de la fenêtre, y compris la possibilité de mettre une image en arrière-plan. Autrement, vous pouvez aussi Option-Déposer une image sur la fenêtre du Terminal pour mettre en place instantanément une image d'arrière-plan.

Cliquez pour positionner le curseur. Cette option doit être activée dans Terminal -> Réglages de la fenêtre -> Emulation. Cochez 'Clic + Option pour positionner le curseur'. Vous pouvez maintenant faire un Option-Clic partout sur la ligne de commande courante pour positionner le curseur à ce point. Cela fonctionne aussi dans des éditeurs tels que Pico et Vim.


Terminaux Alternatifs

Le terminal standard d'OS X est l'application Terminal.app d'Apple mais il y a d'autres alternatives.

Si vous avez installé X11, vous aurez xterm. Xterm est lancé automatiquement lorsque X11 démarre et vous pouvez taper :

$ xterm&

pour obtenir une nouvelle fenêtre Xterm. (N'oubliez pas d'ajouter le & sinon le premier terminal sera bloqué sur l'exécution de Xterm en tâche de fond)

Xterm est très configurable comme en témoigne 'man xterm'

Lancez de nouvelles terminaux Xterm avec Commande-N. Sélectionnez la commande Applications::Customise de X11 pour ajouter de nouvelles commandes au menu Applications. Par exemple, ajoutez :

Name:     xterm
Command:  /usr/X11R6/bin/xterm  -sb -sl 5000 -rightbar -fg white -bg black -geometry 100x50+40+20
Shortcut: n

Maintenant, Commande-N lancera une nouvelle fenêtre Xterm dimensionnée sur 100 colonnes et 50 lignes, positionnée sur les pixels (40,20) à partir du coin haut gauche de l'écran (-geometry 100x50+40+20).

'-fg white -bg black' règle un texte blanc sur un fond noir.

'-sb -sl 5000 -rightbar' règle une barre de défilement sur la partie droite et d'une taille de 5000 lignes.

Xeyes est amusant, regardez les yeux qui suivent votre curseur. Réglez une commande personnalisée comme suit :

Name:     eyes
Command:  /usr/X11R6/bin/xman -bothshown -notopbox
Shortcut: whatever-you-want or blank

Xman est utile, un front end sympa au manuel Unix. Réglez une commande personnalisée comme suit :

Name:     xman
Command:  /usr/X11R6/bin/xman -bothshown -notopbox
Shortcut: whatever-you-want or blank

iTerm est une terminal alternatif.

iTerm

iTerm est un programme d'émulation de terminal pleinement fonctionnel écrit pour OS X en Cocoa. Il supporte l'encodage de langage, l'émulation VT100/ANSI/XTERM et plein d'autres fonctions utiles d'interface utilisateur.

Zterm est utile si vous devez communiquer via un port série ou USB (pour configuer des routeurs par exemple).

Zterm

ZTerm est un programme d'émulation terminal pour le Macintosh. En ces jours, plein de gens l'utilisent pour se connecter à des Bulletin Board Systems et pour télécharger des fichiers. Maintenant nous avons internet. Il est toujours utile pour ces systèmes qui n'offrent que des connexions par dialogue et pour se connecter à des périphériques au travers d'un port série, comme beaucoup de routeurs. Pour les Mac récents qui n'ont pas de port série, ZTerm peut discuter sur des adaptateurs série-USB, avec le logiciel pilote approprié livré avec l'adaptateur.


Les Fichiers .Plist

Les astuces de cette semaine sont dans la continuité des Astuces Mac OS X Quotidiennes notamment les semaines du 28 Février 2003 - Trouble-Shooting (Applications), 7 Mars 2003 - Trouble-Shooting II (System), 14 Mars 2003 - Trouble-Shooting III (Hardware) et 21 Mars 2003 - Trouble Shooting IV (Advanced). (NDT : Ces semaines n'étaient pas encore traduites sur Project:Omega)

Les astuces en rapport avec les problèmes Unix apportent des alternatives en ligne de commande aux méthodes relatées dans les astuces quotidiennes OS X.

La commande 'defaults' permet un accès facile aux fichiers de préférences d'OS X. Elle interprète le code XML permettant ainsi de lire et d'écrire les valeurs de propriété ou de créer de nouvelles propriétés.

$ man defaults

Voir et changer le NSGlobalDomain. Il contient des préférences par défaut qui s'appliquent à une application si elle ne les remplacent pas dans son propre domaine.

$ defaults read -globalDomain
{
    AppleAntiAliasingThreshold = 8; 
    AppleAquaColorVariant = 1; 
    AppleCollationOrder = "en_GB"; 
    AppleHighlightColor = "0.776500 0.776500 0.776500"; 
    AppleICUDateFormatStrings = {
        1 = "yyyy'.'MM'.'dd"; 
        2 = "d' 'MMM', 'yyyy"; 
        3 = "d' 'MMMM', 'yyyy"; 
        4 = "EEEE', 'd' 'MMMM', 'yyyy"; 
...

$ defaults read -globalDomain AppleLocale en_GB
$ defaults write -globalDomain AppleLocale en_US $ defaults read -globalDomain AppleLocale en_US

Voir un fichier .plist avec encodage XML. Cela traduit l'encodage XML en quelque chose de plus lisible.

$ defaults read com.apple.iChat
{
    ABDirectoryResultColumnTitle = "Instant Messaging"; 
    AutoLogin = 1; 
    AutosaveChats = 1; 
    BuddyInfoSelectedTab = 0; 
    "BuddyList.SecondarySortOrder" = 1; 
    "BuddyList.SortOrder" = 3; 
    "BuddyList.Visible" = 1; 
    CardsBlockingPresentityPictures = (
        "60765A82-A567-11D7-A842-000393B2D604:ABPerson", 
        "56C0BB88-C7D2-11D6-950E-000393B2D604:ABPerson"
    ); 
...

NOTE : N'ENREGISTREZ PAS LA VERSION DÉCODÉE DANS LE FICHIER .PLIST DIRECTEMENT, utilisez :

$ defaults write domain 'the-plist-from-defaults-read'

Utilisez vim pour visualiser :

$ defaults read com.apple.iChat | vim -
Vim: Reading from stdin...

Utilisez less pour visualiser :

$ defaults read com.apple.iChat | less
...

Visualiser une seule propriété :

$ defaults read com.apple.iChat AutoLogin
1

Note : 0 = faux/non, 1 = vrai/oui.

Changez une propriété :

$ defaults write com.apple.iChat AutoLogin 0
$ defaults read com.apple.iChat AutoLogin
0

Note : 'defaults' regarde automatiquement dans ~/Library/Preferences et ajoute l'extension plist.

ATTENTION : ne modifiez pas le .plist d'une application active.

Utilisez plutil pour vérifier la syntaxe des fichiers .plist.

$ plutil ~/Library/Preferences/com.apple.iChat.plist
/Users/saruman/Library/Preferences/com.apple.iChat.plist: OK

$ plutil -s ~/Library/Preferences/*.plist

L'option '-s' n'affiche que les erreurs et ne dit rien en cas de succès.


Forcer Quitter

Utilisez 'kill' ou 'killall' pour forcer les applications en rade à quitter.

La commande 'kill' requiert un ID de process, pas un nom d'application. Découvrez le avec :

$ ps xc | grep -iw ical
 6577  ??  S      0:41.67 iCal

(Mettez le nom de l'application entre guillemets s'il contient des espaces ou des caractères spéciaux)

Quittez la avec :

$ kill -QUIT 6577

Forcer-quittez la avec :

$ kill -KILL 6577

Faites en une seule ligne en créant une fonction bash :

$ function killer () { kill -KILL $(ps xc | grep -wi "$*" | awk '{print $1}'); }

$ killer ical

Tuer les applications appartenant aux autres utilisateurs. Ajoutez l'option 'a' à la commande 'ps' pour qu'elle liste aussi les process appartenant aux autres utilisateurs. Vous devez soit être root ou utiliser 'sudo' pour lancer la commande 'kill'.

Tuer un process par son nom. Utilisez la commande 'killall'.

$ killall ical
No matching processes belonging to you were found

$ killall iCal

(Killall est sensible à la casse)

Killall peut aussi trouver les process par le nom en utilisant des expressions régulières - regardez dans la page man.

Pour éteindre l'ordinateur à partir de la ligne de commande :

$ sudo shutdown -r now

Association de Lancement et de Fichier

Le Finder et la commande 'open' utilisent tous les deux les Launch Services pour associer des documents à des applications. Le Finder utilise aussi cette information pour associer des icônes à des documents.

La commande 'lsregister' peut être lancée à la ligne de commande et donne la portée pour une maintenance manuelle de la base de données des Launch Services.

Les problèmes dus à des icônes incorrectes ou des documents qui ne peuvent être ouverts (avec la bonne application) peuvent être résolus avec 'lsregister'

$ /System/Library/Frameworks/
ApplicationServices.framework/Versions/A/
Frameworks/LaunchServices.framework/Versions/
Current/Support/lsregister

(et tout sur une même ligne)

lsregister: [OPTIONS] [-domain { system | local | user | network }]... [path]...
Recherche dans les chemins d'accès des bundles d'application et 
ajoute chaque élément trouvé dans la base de données des Launch Services
Pour des spécifications de domaine, demandez à CF la liste des emplacements
d'application dans le(s) domaine(s) donné(s).

-kill Réinitialise la base globale des Launch Services avant de faire quoi que ce soit. -lint Affiche des infos sur les erreurs plist en enregistrant les bundles. -convert Enregsitre les applications trouvées dans les fichiers de la base de données LS. -load Charge le service de plugin des LaunchServices si ce n'est déjà fait. -lazy n Fait une pause de n secondes avant d'enregistrer les applications si le cache local est déjà rempli. -r Enregistre récursivement le contenu des répertoires, n'explore pas les packages et les répertoires invisibles -R Enregsitre récursivement le contenu des répertoires, y compris le contenu des packages et des répertoires invisibles. -f Force la mise à jour des données d'enregistrement même si la date de modification est inchangée. -v Affiche la progression des traitements. -dump Affiche le contenu complet de la base après enregistrement. -h Affiche cette aide.

Le fait de taper la commande :

...the/long/path/lsregister -kill -r -domain system -domain local -domain user

réparera la base de données des Launch Services.

Je n'ai pas plus exploré cette commande mais elle permet d'interroger, de maintenir et de réinitialiser la base de données des LS.


Gardez la Propre

Unix sait déjà bien s'auto-maintenir. Une petite maintenance périodique est requise et est programmée pour être lancée à des heures matinales quotidiennement, hébdomadairement et mensuellement.

La programmation est contrôlée par le programmateur système 'cron', qui tire ses informations de programmation dans /etc/crontab:

$ cat /etc/crontab 
# /etc/crontab
SHELL=/bin/sh
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin
HOME=/var/log
#
#minute hour    mday    month   wday    who     command
#
# Run daily/weekly/monthly jobs.
15      3       *       *       *       root    periodic daily
30      4       *       *       6       root    periodic weekly
30      5       1       *       *       root    periodic monthly

Si votre Mac est éteint durant ces heures, vous souhaiterez peut-être reprogrammer cette maintenance périodique. Voir :

$ man 5 crontab

pour une explication du format de crontab.

Autrement, lancez la maintenance manuellement avec :

$ sudo periodic daily
$ sudo periodic weekly
$ sudo periodic monthly

Parmis les candidats au retrait, on trouve les fichiers log dans /var/log qui sont périodiquement zippés et archivés de manière rotative. Par exemple, trouvez tous les fichiers log de plus de 10 Mb :

$ find /var/log -size +20000
/var/log/named/default.log
/var/log/secure.log

Obtenez plus de details avec :

$ find /var/log -size +20000 -ls

Installez 'anacron'. Il peut être obtenu à partir des nombreux portages d'Unix y compris chez fink.

C'est semblable à cron sauf qu'il traite les évènements programmés qui n'ont pas été traités lorsque votre Mac dormait ou était actif.

$ fink describe anacron
Information about 1951 packages read in 4 seconds.

anacron-2.3-4: Periodic command scheduler
Anacron exécute des commandes à des intervalles spécifiés en jours. A l'inverse de cron, il ne suppose pas que le système est actif de manière continue. Il est idél pour des machines telles que les portables...

Retirer les caches Navigateur. Je lance pratiquement tous les navigateurs pour mes tests de développement web. En conséquence, le cache des navigateurs augmente beaucoup le temps des backups incrémentaux. J'ai écrit un simple script qui retire le cache de Camino, FireFox, iCab, Internet Explorer, Mozilla, Omniweb 5, Opera 7 et Safari.

#!/bin/bash

if [ "$1" = "-usage" ]; then echo "Cleans the caches for the browsers:" echo "Camio, Firebird, iCab, IE, Mozilla, OmniWeb5, Opera, Safari" echo "Usage: ${0##*/}" exit fi
# just in case! cd ~/Library || exit 1
echo "Removing caches..."
# Camio echo -n " Camio - " { cd ~/Library/Application Support/Chimera/Profiles/default/ && rm -r $(ls -d *.slt | head -1)/Cache && echo removed; } 2> /dev/null || echo "none"
# Firefox echo -n " Firefox - " { cd ~/Library/Application Support/Firefox/profiles/*default/ && rm -r Cache && echo removed; } 2> /dev/null || echo "none"
# iCab echo -n " iCab - " { rm -r ~/Library/Preferences/iCab Preferences/iCab Cache/ && echo removed; } 2> /dev/null || echo "none"
# Interner Explorer echo -n " Internet Explorer - " { rm ~/Library/Caches/MS Internet Cache/IE Cache.waf && echo removed; } 2> /dev/null || echo "none"
# Mozilla echo -n " Mozilla - " { cd ~/Library/Mozilla/Profiles/default/ &&| rm -r $(ls -d *.slt | head -1)/Cache && echo removed; } 2> /dev/null || echo "none"
# OmniWeb echo -n " Omniweb - " { rm -r ~/Library/Caches/com.omnigroup.OmniWeb5/Cache.bundle && echo removed; } 2> /dev/null || echo "none"
# Opera echo -n " Opera - " { rm -r ~/Library/Caches/Opera Cache && echo removed; } 2> /dev/null || echo "none"
# Safari echo -n " Safari - " { rm -r ~/Library/Caches/Safari && echo removed; } 2> /dev/null || echo "none"
echo "Done."

Les lieux des fichiers cache sont corrects en ce qui me concerne mais je ne suis pas sûr des variations appliquées aux noms de dossier par la famille des navigateurs Mozilla.


Disque Durs

/Applications/Utilities/Utilitaire de disque permet de vérifier et réparer les permissions sur le volume système et, de vérifier et réparer la structure d'autres volumes. Ces fonctions peuvent être lancées à la ligne de commande avec 'diskutil'.

Pour désigner un disque/volume spécifique, spécifiez son point de montage, son identifiant ou noeud de périphérique comme suit.

Le point de montage est en général /Volumes/disc-name, mais dans mon cas, je l'ai monté directement sous /.

$ diskutil verifyDisk /Music/
Started verify/repair on disk disk0s9 Music-saruman
Checking HFS Plus volume.
Checking Extents Overflow file.
Checking Catalog file.
Checking Catalog hierarchy.
Checking volume bitmap.
Checking volume information.
The volume Music-saruman appears to be OK.
Verify/repair finished on disk disk0s9 Music-saruman

Pour découvrir l'identifiant d'un disque et son noeud de périphérique, utilisez disktool.

$ disktool -l
...
***Disk Appeared ('disk0s3',Mountpoint = '/', fsType = 'hfs', volName = 'OSX-saruman')
***Disk Appeared ('disk0s5',Mountpoint = '/Users', fsType = 'hfs', volName = 'Users-saruman')
***Disk Appeared ('disk0s7',Mountpoint = '/Games', fsType = 'hfs', volName = 'Games-saruman')
***Disk Appeared ('disk0s9',Mountpoint = '/Music', fsType = 'hfs', volName = 'Music-saruman')

$ diskutil verifyDisk disk0s9 Started verify/repair on disk disk0s9 Music-saruman Checking HFS Plus volume. ... Verify/repair finished on disk disk0s9 Music-saruman
$ diskutil verifyDisk /dev/disk0s9 Started verify/repair on disk disk0s9 Music-saruman Checking HFS Plus volume. ... Verify/repair finished on disk disk0s9 Music-saruman

Pour une réparation, utilisez :

$ diskutil repairDisk /Music Started verify/repair on disk disk0s9 Music-saruman
Checking HFS Plus volume.
Checking Extents Overflow file.
Checking Catalog file.
Checking Catalog hierarchy.
Checking volume bitmap.
Checking volume information.
The volume Music-saruman appears to be OK.
Verify/repair finished on disk disk0s9 Music-saruman

Pour vérifier et réparer les permissions (du volume de démarrage), utilisez :

diskutil verifyPermissions /OSX-saruman
diskutil repairPermission /OSX-saruman

NOTE : le nom de votre volume système ne sera pas le même que le mien.

Pour réparer le volume de démarrage, vous devez redémarrer en mode 'single user'. Il n'est pas possible de réparer un volume qui est monté et qui ne peut être démonté (car il est toujours en utilisation).

Redémarrez en maintenant enfoncée la combinaison Commande-S et attendez que le texte finisse de défiler sur votre écran. Ensuite, montez le volume système en mode écriture (il est actuellement monté en mode lecture-seule à ce stade du process de démarrage).

Tapez :

$ mount -uw /

Puis vérifiez/réparez le système de fichier avec :

$ fsck -y

ou, pour les systèmes de fichiers journalisés (par défaut dans Pather) :

$ fsck -fy

Si fsck indique des problèmes du genre :

***** FILE SYSTEM WAS MODIFIED *****

relancez fsck jusqu'à ce qu'il indique qu'aucune modification n'était nécessaire.

Tapez contrôle-d pour continuer le process de démarrage ou tapez :

$ reboot

Réparez les autres volumes. Quelques fois, il n'est pas possible de réparer d'autres volumes car ils ne peuvent pas être démontés (par exemple, si vous avez placé votre répertoire départ sur une autre partition). Dans ce cas, le volume en question doit être réparé en mode 'single user' comme pour le volume système.

Par exemple, pour réparer HFS disc 0 partition 9 :

fsck_hfs -fy /dev/rdisk0s9

Référez-vous à 'disktool' au-dessus pour obtenir les numéros du disque et de la partition, ou utilisez la commande 'df' en mode 'single user'.


Commandes Fichiers et Répertoires Basiques

Les quatre semaines à venir vont constituer une référence de commandes Unix en listant les commandes utiles par type d'utilisation. Il y a tellement de commandes disponibles qu'il n'est pas possible de toute les connaître ni même de se rappeler celles que l'on a découvertes et utilisées le mois dernier.

Reportez-vous au reste des astuces pour obtenir un grand nombre d'exemple d'utilisation de ces commandes.

Et, bien sûr, n'oubliez pas le manuel Unix 'man'.

ls ... liste le contenu du répertoire courant.
Option -l (l comme lundi) pour une liste plus détaillée
Option -a pour lister les fichiers cachés, -A pour éviter de lister '.' et '..'
Option -L pour suivre les liens symboliques
Option -F pour identifier différents types de fichiers ou
Option -G pour une identification par couleur

cp ... copie les fichiers et les répertoires
Option -R pour une copie récursive pour copier toute l'arborescence du répertoire

mv ... déplace ou renomme des fichiers et des répertoires
Renommez un fichier, déplacez le dans un autre répertoire ou faites les deux en même temps

rm ... supprime des fichiers et des répertoires
Option -R ou -r pour déplacer le répertoire et ses sous-répertoires
Option -f pour contourner les permissions lorsque cela est possible
Option -i pour une confirmation interactive de chaque suppression

cd ... change de répertoire courant
'cd..' pour remonter dans l'arborescence
'cd' pour aller dans votre répertoire départ
'cd -' pour retourner dans le dernier répertoire

pwd ... affiche le répertoire de travail
Affiche le répertoire courant

pushd ... change de répertoire et l'empile Chaque fois que pushd est appelée, le répertoire courant est mémorisé dans la pile de répertoire Utilisez popd pour revenir sur vos pas

popd ... revenir au dernier répertoire empilé 'pushd' et 'popd' travaille sur une pile système où le dernier répertoire mémorisé est le premier à être extrait

dirs ... affiche la pile de répertoire
Ceci est la pile où 'pushd' écrit et dans laquelle 'popd' lit

mkdir ... crée un nouveau répertoire
Option -p pour faire plusieurs répertoires (imbriqués) d'un seul coup

rmdir ... supprime un répertoire
Le répertoire doit être vide
Utilisez 'rm -r' pour supprimer des répertoires non vides

chmod ... change les permissions d'un fichier et d'un répertoire
Option -R pour changer les permissions de toute l'arborescence d'un répertoire
Option -L pour suivre les liens symboliques
Option -h pour changer le mode d'un lien au lieu du fichier qui est pointé

chown ... change le propriétaire d'un fichier et d'un répertoire
Options -R, -L et -h comme poour 'chmod'
Changez à la fois le propriétaire utilisateur et groupe et spécifiant user-owner:group-owner

chgrp ... change le groupe propriétaire de fichiers et de répertoires
Options -R, -L et -h comme pour 'chmod'

chflags ... change les flags d'un fichier
Les fichiers et les répertoires Unix sont dotés de plein de flags tels que non-modifiable, ajout-seulement, archivé qui peuvent être réglés avec cette commande
Options -R et -L comme pour 'chmod'


Commandes de Visualisation de Fichiers

cat ... affiche le contenu d'un fichier
Cat concatène en fait plusieurs fichiers et en écrit le résultat sur la sortie standard (l'écran)
Redirigez vers un fichier pour réellement joindre les fichiers
Option -b pour compter les lignes non blanches
Option -s pour réduire plusieurs lignes blanches
Option -v pour afficher les caractères non affichables et les rendre visibles

more ... affiche le contenu d'un fichier page par page
Faites défiler vers le haut et vers le bas avec les touches fléchées
Montez d'une page ou descendez d'une page avec les touches 'u' et 'd'
Recherchez un texte avec /texte-à-rechercher
Et beaucoup, beaucoup plus encore, voir 'man more'

less ... affiche le contenu d'un fichier page par page
Comme more, mais beaucoup plus que more
Voir 'man less'

lesskey ... spécifie les associations de de clé pour less
Spécifiez des associations de clés alternatives pour contrôler less

head ... affiche les 10 premières lignes d'un fichier
Option -n spécifie un nombre différent de lignes à afficher

tail ... affiche les 10 dernières lignes d'un fichier
Option -n spécifie un nombre différent de lignes à afficher

zcat, zmore ... cat et more sur des fichiers zippés

bzcat, bzmore, bzless ... cat, more, less sur des fichiers bzippés

wc ... compte les lignes, les mots et les caractères de fichiers
Options -l, -w et -c pour contrôler ce qui est compté

file ... détermine le type d'un fichier

pr ... affiche les contenu de fichiers avec pagination
Affichez des fichiers page par page avec une entête et un pied de page

vis ... affiche des fichiers contenant des caractères non affichables
Fait un meilleur boulot que 'cat -v'

strings ... recherche des chaînes de caractères affichables dans un fichier binaire
Option -a pour rechercher dans tout le fichier et non seulement dans les sections binaires (applicable principalement aux executables)

hexdump ... affiche des fichiers binaires
La sortie montre la valeur héxadécimale de chaque octet
Option -n x pour n'afficher que les 'x' premiers octets

xxd ... affiche des fichiers binaires
Comme 'hexdump' mais affiche à la fois la représentation héxadécimale et le caractère correspondant de chaque octet (ou "." pour les caractères non affichables)

(Voir semaine 95)

emacs ... puissant éditeur de texte

vi/vim ... le meilleur des éditeurs de texte
(Voir semaines 50, 53 et 69)

pico ... un éditeur de texte simple


Commandes pour Comparer des Fichiers Texte

split ... scinde un fichier en plusieurs fichiers
Scinde un grand fichier en plusieurs petits fichiers de 1000 lignes chacun
Option -l pour spécifier une longueur différente pour les petits fichiers

sort ... trie les lignes d'un fichier en ordre alphabétique
Chaque ligne est considérée comme un nombre de colonnes, vous pouvez donc trier sur une colonne particulière ou une clé
Option -t pour spécifier la clé séparatrice (espace, commande, tabulation, etc)
Option -k pour spécifier quelle colonne/clé trier
Option -b pour ignorer les espaces placés en début de ligne
Option -f pour ignorer la casse (rendre le tri insensible à la casse)
...et plus encore....

uniq ... filtre en sortie les lignes multiples d'un fichier
Le fichier doit d'abord être trié
Dès que des lignes multiples sont repérées, seule la première ligne n'est affichée
Option '-f fields' pour ignorer les premiers champs 'fields' de chaque ligne dans la comparaison
Option '-s chars' pour ignorer les premiers caractères 'chars' de chaque ligne dans la comparaison
Option -c pour précéder chaque affichage de ligne du nombre de répétitions trouvées dans le fichier

join ... effectue une jointure de base de données sur des fichiers
Spécifiez un champ (comme dans 'sort') par lequel les fichiers sont comparés
Une ligne est affichée pour chaque paire de lignes des deux fichiers lorsque les champs de comparaison correspondent

paste ... fusionne les lignes correspondantes de deux fichiers

comm ... affiche les lignes communes à deux fichiers
Les deux fichiers doivent d'abord être triés
Trois colonnes sont produites pour les lignes qui ne sont que dans le fichier 1, puis que dans le fichier 2, et à la fois dans les deux fichiers
Options -1, -2, -3 pour supprimer l'affichage d'une des trois colonnes

diff ... compare deux fichiers
Compare deux fichiers et affiche les différences en termes de petites differences dans les lignes, nouvelles lignes, lignes effacées
Utilisez pour comparer deux versions du même fichier
Option -b pour ignorer les différences produites par les espaces
Option -B pour ignorer les différences produites par des lignes blanches
Option -i pour ignorer les changements dus à la casse

diff3 ... compare trois fichiers
Comparaison entre trois fichiers f1, orig et f2, compare les différences entre f1 et f2 relatives à orig
Option -A pour incorporer tous les changements entre orig et f2 dans f1 - cela agit comme une opération de fusion mais uniquement sur les différences détéctées dans f2 (relative à orig) dans f1

sdiff ... compare et fusionne deux fichiers
Compare les différences entre deux fichiers et les fusionne dans un troisième
Option -b pour ignorer les différences produites par les espaces
Option -B pour ignorer les différences produites par des lignes blanches
Option -i pour ignorer les changements dus à la casse

(Voir semaines 26 et 35)

zdiff, bzdiff ... différences entre des fichiers zippé ou bzippés


Commandes pour Rechercher du Contenu

grep ... recherche du texte dans un fichier
Recherche un texte spécifique ou un modèle spécifié par une expression régulière (voir 'man re_format')
Option -i pour spécifier une insensibilité à la casse
Option -w pour une recherche sur des mots entiers
Option -r pour une recherche dans tous les sous-répertoires d'un répertoire
Option -v pour afficher les lignes qui NE correspondent PAS
Options -n, -l, -L, -h, -H pour contrôler ce qui est affiché en termes de texte correspondant, de noms de fichiers et de numéros de ligne
Option -E pour utiliser les expressions régulères étendues au lieu des basiques
Option -F pour utiliser des chaînes fixes (plus rapide que la recherche par modèle)

egrep ... recherche du texte dans un fichier
Même chose que 'grep -E', elle utilise utilise les expressions régulières étendues

fgrep ... recherche du texte dans un fichier
Même chose que 'grep -F'

(Voir les semaines 9 et 10)

zgrep, bzgrep ... grep dans un fichier zippé ou bzippé

bzegrep ... egrep dans un fichier bzippé

bzfgrep ... fgrep dans un fichier bzippé

perl ... un langage de manipulation de texte
Tiré des pages man :
Perl est un langage optimisé pour scanner des fichier texte arbitraires, extraire des informations de ces fichiers et afficher des rapports basés sur ces information. C'est aussi un bon langage pour beaucoup de tâches de gestion de systèmes. Le langage a plus pour but d'être pratique (facile à utiliser, efficace, complet) is intended to be practical (easy to use, efficient, complete) que d'être beau (petit, élégant, minimal).


Commandes pour Changer du Contenu

awk ... langage de recherche et de manipulation basé sur des modèles
Awk lit un fichier texte ligne après ligne et applique une série d'opérations de recherche, de remplacement et d'édition aux lignes qui correspondent aux critères donnés.
Awk peut lire un fichier script pour obtenir les commandes de traitement
le language combine un langage de programmation dans le style du C avec en plus des expressions régulières de recherche et de remplacement.
(Voir les semaines 86 et 87)

gawk, nawk ... variations de awk
Non disponibles dans l'installation standard de Mac OS X

sed ... éditeur de flux
Sed lit un fichier texte ligne après ligne et applique une série d'opérations de recherche, de remplacement et d'édition aux lignes qui correspondent aux critères donnés.
Sed peut lire un fichier script pour obtenir les commandes de traitement
le language utilise les expressions régulières pour ses fonctionnalités de recherche et de remplacement mais ne comporte pas d'instructions de programmation dans le style du C.
(Voir semaines 85 et 89)

tr ... transforme un caractère en un autre
Lit un fichier texte et transforme toutes les occurences d'un caractère donnée en un autre
Par défaut, tr lit l'entrée standard et écrit sur la sortie standard, donc une redirection est nécessaire pour travailler avec d'autres fichiers
N'écrivez pas la sortie sur le fichier entrée sinon il finira vide

col ... retire des caractères
Col peut être utilisé pour nettoyer des fichiers
Option -b pour retirer des caractères effacement multiples comme affiché par les pages man
Option -x pour convertir les caractères tab en plusieurs espaces

(Voir semaine 10)

cut ... filtre les colonnes de fichiers
Cut peut traiter un fichier comportant des colonnes de texte (par exemple, une table dont les colonnes sont séparées par des tabulations) et en extraire que la colonne spécifiée
Option -f pour lister les colonnes à afficher, comme '-f 3,5' pour 3 et 5, '-f 3-5' pour 3 à 5 ou '-f 1,3-5' pour 1 et 3 à 5.
Option -d pour spécifier le champ de séparation (tab par défaut), comme '-d " "' pour l'espace ou '-d ","' pour la virgule

expand ... transforme les tabulations en espaces

unexpand ... compresse les espaces en tabulations

fmt ... formatte un fichier texte
Lit un fichier et écrit une version dont les lignes ne dépassent pas un nombre spécifié de caractères ou, éventuellement, n'ont pas une longueur inférieure à une longueur donnée
Option -c pour center le texte
Option -p pour permettre des paragraphes indentés
Option -s pour réduire plusieurs espaces dans les lignes

fold ... réduit les lignes longues
Version simple de fmt qui réduit les lignes longues à 80 caractères ou moins
Option -w pour spécifier une longueur maximum autre que 80


Commandes de Recherche de Fichiers

La semaine dernière et les trois semaines à venir constitueront une référence des commandes Unix avec classement des commandes par zones d'intérêt utilisateur. Il y a tellement de commandes disponibles qu'il sera impossible de toute les référencer ni même de se rappeler celles que l'on connaissait et utilisait le mois dernier.

Reportez-vous aux autres astuces pour obtenir plein d'exemples d'utilisation de ces commandes.

Consultez le Learning Centre pour des tutoriaux et explications des autorisations Unix.

Et bien sûr, n'oubliez pas le manuel Unix 'man'.

Pour rechercher des fichiers dans le système de fichiers, utilisez :

find ... trouve les fichiers correspondants à certains critères
Option -E pour spécifier des expressions régulières étendues
Option -L pour interpréter les liens symboliques des fichiers trouvés
Option -X lorsque find est utilisé avec xargs
Option -s pour scruter les hiérarchies dans l'ordre lexicographique (dictionnaire)

Vérifiez les nombreuses primaires qui spécifient les fichiers devant correspondre en se basant sur plein plein de critères tels que name, time/date, owners, size, type, permissions, etc
(Voir les semaines 1, 13, 31, 49, 97, 98)

locate ... recherche dans une base de données de fichiers
Cela repose sur la base locate devant être à jour
(Voir semaine 1)

locate.updatedb ... met à jour la base de données locate

La meilleure façon de mettre à jour la base de données locate afin d'éviter de révéler des noms de fichier privés consiste en la commande :
$ sudo periodic weekly

(Voir semaines 64, 88)

type ... cherche un exécutable (shell bash uniquement)
Option -a pour trouver toutes les versions de l'exécutable
(Voir semaine 77 - Mardi)

which ... cherche un exécutable (csh et tcsh)
(Voir semaines 20 et 47 - Lundi)

whereis ... cherche un exécutable (cherche dans le chemin d'accès système)

Aussi :

ls -r * ... listing récursif d'un répertoire

echo * ... liste tous les fichiers du répertoire courrant


Commandes à propos et pour Utilisateurs

id ... affiche l'identité de l'utilisateur courant
Option -p pour afficher dans un format plus lisible
Option -G pour afficher les numéros de groupes, utile pour les scripts shell

groups ... affiche les groupes auxquels un utilisateur appartient

(Voir semaine 17)

logname ... affiche le nom de connexion de l'utilisateur courant

finger ... affiche des informations sur un utilisateur
Créez les fichiers ~/.plan et ~/.project pour donner plus d'informations à finger

passwd ... change le mot de passe de l'utilisateur courant

chpass, chfn, chsh, ... ajoute ou change les informations utilisateur
Vérifiez les pages man pour la compatibilité avec OS X

umask ... change le umask pour ce process et ses process fils
(Voir semaine 47 - Mercredi)

login ... connecte à la machine
Option -p pour hériter de l'environnement courant

rlogin ... connecte à une machine distante
Préférez plutôt le plus sécurisé 'ssh' - voir à "Commandes Réseau" plus loin dans cette série.

su ... change d'identité

sudo ... exécute une commande en étant sous root
Option -s pour lancer un shell avec le nouvel utilisateur
Option -u pour lancer avec un utilisateur particulier à la place de root
Option -l pour lister ce que vous êtes autorisé à faire avec sudo
Options -k, -K pour limiter dans le temps la validité du mot de passe

users ... affiche qui est actuellement connecté
who ... comme 'users' mais avec plus de détails
w ... comme 'who' avec encore plus de détails

whoami, who am i ... utile pour les amnésiques

last ... liste toutes les connexions, avec date, heure et status

(Voir semaine 17)

write ... envoie un message à un autre utilisateur
Utilisez 'who' pour lister d'autres utilisateurs et leur console
(Voir semaine 95 - Vendredi)

wall ... envoie un message à tous les utilisateurs

talk ... discute avec un autre utilisateur
Utilisez 'who' pour lister d'autres utilisateurs et leur console

mesg ... autorise/interdit l'envoie de messages pour d'autres utilisateurs


Commandes Utilitaires Pratiques

man ... le manuel Unix
Option -k pour rechercher dans le manuel
Option -f pour n'avoir qu'un résumé sur une seule ligne d'une commande

apropos ... l'équivallent de man -k
Cette commande et 'man -k' recherche une commande donnée et affichera toutes les lignes contenant cette chaîne de caractères

whatis ... l'équivalent de man -f
Cette commande et 'man -f' recherche la commande donnée en tant que mot entier

makewhatis ... (re)construit la base de données de whatis

(Voir les semaines 2 et 20)

catman ... crée une version formattée des pages man
Accélère la commande 'man'.

info ... le manuel GNU en ligne
Essayez 'info info' pour plus de détails
Essayez 'info nom-de-commande' pour des infos sur la commande (GNU)

at ... exécute une commande à un moment donné

atq ... liste les tâches en attente lancées par 'at'

atrm ... retire une tâche 'at' de la file d'attente

atrun ... me démon qui lance les tâches 'at'
Cela devrait être ajouté au crontab système et lancé périodiquement (disons toutes les 5 minutes) pour lancer les tâches 'at'.

calendar ... service de programmation et de rappel

(Voir semaine 41)

cron ... démon de programmation des tâches système

crontab ... démon de programmation des tâches utilisateurs

(Voir semaine 33)

leave ... vous rappelle quand il est temps de partir
As t'on besoin de s'en rappeler ? :-)
(Voir semaine 95 - Mercredi)

banner ... écrit une bannière de texte sur une imprimante

bc ... une calculatrice à précision arbitraire

dc ... une autre calculatrice à précision arbitraire

cal ... affiche un calendrier mensuel ou annuel
Option -j affiche les numéros de jour

units ... convertit des quantités d'un système d'unité à un autre

(Voir semaine 6)


Commandes pour Contrôler le Terminal

clear ... efface la fenêtre du terminal

resize ... redimensionne la fenêtre du terminal
Option -s pour spécifier seulement le nombre de lignes et de colonnes
$ resize -s 50 10

stty ... change le réglage du terminal
Option -a pour afficher les réglages courants
Option -g pour afficher sous une forme qui peut être utilisée par -f
Option -f pour régler les commandes à partir d'un fichier

reset ... réinitialise l'affichage du terminal
Utile après avoir accidentellement affiché un fichier binaire qui a fouttu la pagaille dans les réglages

tty ... affiche le terminal courant de l'utilisateur

toe ... affiche toutes les informations terminal (terminfo) classées par nom
Lit la base de données compilée terminfo dans /usr/share/terminfo/...

tic ... compilateur terminfo
Lit les descriptions terminfo et les compile dans la base de données terminfo dans /usr/share/terminfo/...

infocmp ... compare et affiche les descriptions terminfo

captoinfo ... convertit une description termcap en une description terminfo

infotocap ... convertit une description terminfo en une description termcap

tput ... interroge la base de données terminfo


Commandes pour Contrôler le Shell

alias ... transforme une ligne de commande en un mot clé
(Bash et tcsh)

function ... assigne une fonction à un mot clé
(Bash seulement)

(Voir les semaines 12, 20, 71, 77, 99 - Mardi)

tee ... découpe un pipe en plusieurs jets
Peut être utilisé pour diriger la sortie d'une commande vers un fichier et vers le terminal en même temps

set ... régle une variable shell
unset ... retire une variable shell
setenv ... régle une variable d'environnement shell
unsetenv ... retrire une variable d'environnement shell

(tcsh seulement)
(Voir semaine 54 - Lundi)

expect ... permet d'entrer les réponses attendues par des programmes interactifs

script ... transforme une session terminal en un transcript

bindkey ... pour changer la fonctionnalité key du shell

batch ... exécute des commandes pendant les moments d'inactivité
La commande est retardée jusqu'à ce que le niveau de charge du système soit bas.
Le niveau de charge est contrôlé par atrun, voir l'astuce de Mercredi.

exec ... exécute une commande à la place du shell

nohup ... exécute une commande qui ira jusqu'à sa fin quoi qu'il arrive
La commande ne sera pas stoppée par 'kill -HUP' ou lorsque le shell en cours sera terminé
(Voir semaine 78)

lockfile ... empêche un fichier d'être accédé par plus d'un process

rehash ... rafraîchit la liste des exécutables du shell
(tcsh)
(Voir semaine 21 - Vendredi)

hashstat ... donne des statistiques d'accès à hash
(tcsh)

exit ... termine un shell non interactif

logout ... termine un shell interactif


Commandes d'Infos sur Machines et Disques

Les deux dernières semaines et les deux prochaines constitueront une référence des commandes Unix en listant de nombreuses commandes par type d'usage spécifique. Il y a tant de commandes disponibles qu'il serait impossible de toute les connaître ou même de se rappeler de celles que l'on a utilisées le mois dernier.

Reportez-vous au reste des astuces pour avoir de nombreux exemples d'utilisation de ces commandes.

Et bien sûr, n'oubliez pas de consulter le manuel Unix 'man'.

Pour obtenir des informations sur une machine (hôte), comprenant le matériel, le système d'exploitation et le noyau, utilisez :

arch ... affiche l'architecture de la machine

machine ... affiche le type de processeur

uname ... affiche le nom de l'OS, sa version et le type de processeur
Option -a pour afficher plein (toutes) d'informations

hostinfo ... affiche des infos sur le noyau de l'hôte

Les commandes ci-dessus sont souvent utilisées par les systèmes 'make' et './configure' pour permettre la construction du binaire adéquate en fonction de la plate-forme.

hostname ... règle et affiche le nom réseau de l'hôte
Option -s pour afficher le nom d'hôte sans le nom de domaine

uptime ... affiche depuis combien de temps a été utilisé le système

date ... affiche et règle la date système

AppleSystemProfiler ... affiche des détails compréhensibles
Cette commande n'est plus incluse dans Panther. Elle est incorporée dans la commande Informations Système
située dans Applications:Utilitaires (ou dans la fenêtre À propos de ce Mac).

(Voir la semaine 11)

ioreg ... montre l'inscription e/s de tous les matériels

Pour des infos sur l'utilisation des disques, utilisez :

du ... affiche des statistiques d'utilisation d'un disque
Option -a pour un rapport avec tous les fichiers de la hiérarchie
Option -c pour afficher un grand total
Option -h pour afficher les tailles de fichiers en K-, M- et G-octets
Option -s * pour afficher des informations sur chaque fichier

df ... affiche des informations sur les espaces libres de tous les disques
Option -h pour afficher les tailles de fichiers en K-, M- et G-octets
Option -i pour afficher des statistiques sur les inode aussi

(Voir semaine 5)

fsck ... pour vérifier et réparer les systèmes de fichiers
Option -f pour forcer la vérification, utile pour des périphériques journalisés
Option -y pour terminer la vérification sans intervention manuelle
(Voir semaines 55 et 100)

mount ... affiche des informations sur les périphériques montés
En plus de monter les périphériques, la commande mount en tant que telle montre des informations sur chaque périphérique monté y compris s'il est local et s'il est journalisé.
(Voir semaines 56 et 84)

disktool -l ... liste les disques
Disktool fait partie de l'interface en ligne de commande d'Apple au système de fichiers.
(Voir semaine 22)


Commandes Statistiques Système et Noyau

Ces commandes affichent des informations sur le système, la mémoire et les fichiers.

sc_usage ... affiche des stats sur les appels systèmes en temps réel
Par exemple, 'sudo sc_usage TextEdit'

fs_usage ... affiche des stats sur l'utilisation du système de fichier en temps réel
Par exemple, 'sudo fs_usage TextEdit' puis lancez textedit et ouvrez/enregistrez des fichiers.

lsof ... liste les fichiers ouverts
Par exemple 'lsof' ou 'lsof /dev/console'

fstat ... affiche le statut d'un fichier
Par exemple 'fstat' ou 'fstat ~' or 'fsstat ~/letter.doc'

vm_stat ... affiche des statistiques sur la mémoire virtuelle
Observez les pages qui augmentent de 100 fois par seconde : vous devez acheter plus de mémoire ou exécuter moins de programmes.

(Voir semaine 88)

latency ... affiche les commutations et les interruptions du contexte
Doit être lancé sous root

dmesg ... affiche le buffer des messages système
(Voir astuce semaine 61 - Vendredi)

ac ... affiche le temps de connexion utilisateur

Ces commandes opèrent sur le noyau.

ktrace ... effectue un suivi du noyau
Par exemple, 'ktrace ls' exécute 'ls' et suit son activité noyau. Cela produit le fichier 'ktrace.out'.

kdump ... affiche un fichier 'ktrace.out' lisible par un humain
Par exemple 'kdump' si le fichier de suivi est dans le répertoire courant.
Option -f pour spécifier le fichier de suivi

zprint ... affiche des informations sur des zones du noyau

sysctl ... affiche et règle les variables d'état du noyau
Option -a pour afficher toutes les variables d'état et leur réglage courant

kextload ... chargement d'une extension noyau

kextunload ... déchargement d'une extension noyau

kextstat ... affiche des statistiques sur une extension noyau


Commandes pour Lancer des Process

kill ... arrête/redémarre des process par leur PID
Envoie un signal au process. Donne le n° ou le nom du signal, et le PID (Process ID) du process à tuer.

man 2 sigaction ... informations sur les signaux
Utilisez cette commande pour en apprendre sur les signaux possibles que 'kill' puisse envoyer aux process actifs.

killall ... arrête/redémarre des process par leur nom
Comme "kill" mais un nom de process sensible à la casse est requis à la place du PID.

(Voir semaine 45)

ps ... liste les process actifs
Option -x pour lister aussi les process non attachés au terminal
Option -a pour lister les process appartenant à d'autres utilisateurs
Option -ww pour faire un listing large, sinon l'affichage est tronqué
Option -c pouor lister seulement le nom du process (la commande), au lieu de la commande en ligne complète

top ... affiche des infos sur les process actifs

(Voir semaine 19)

nice ... exécute un process avec une priorité donnée

renice ... modifie la priorité d'un process actif

exec ... exécute une commande à la place du shell

(Voir semaine 47)

nohup ... exécute une commande qui sera insensible aux arrêts
La commande ne sera pas stoppée par 'kill -HUP' ou lorsque le shell courant se terminera
(Voir semaine 78)

leaks ... vérifie les trous de mémoire d'un process
Par exemple 'leaks TextEdit'

heap ... liste la mémoire allouée au process
Par exemple 'heap TextEdit'

printenv ... affiche l'environnement du shell courant


Commandes Réseau

curl ... va chercher une URL sur un serveur distant
Supporte les protocoles suivants :
HTTP, HTTPS, FTP, GOPHER, DICT, TELNET, LDAP, FILE
Par exemple : 'curl http://www.apple.com'

wget ... va chercher une URL sur un serveur distant
Comme curl, mais n'est pas inclus dans OS X. Disponible pour OS X via des portages tels que Fink.

fetchmail ... va chercher les emails sur des serveurs SMTP, POP, IMAP etc

tin... lit des newsgroups Usenet

trn ... lit des newsgroups Usenet

ftp ... protocole de transfert de fichiers
Client FTP en ligne de commande pour récupérer des fichiers de serveurs distants
(Voir semaine 63)

ftpd ... démon ftp
Lance un service ftp
(Voir semaine 94)

telnet ... se connecte en utilisant le protocole telnet
Se connecte à des machines distantes qui exécute telnet ou se connecte à des ports spécifiques pour tester des services tels que FTP, SMTP et HTTP manuellement.

ssh ... démarre un shell sécurisé sur une machine distante
La session est encryptée, y compris le transfert du mot de passe utilisé pour se connecter sur la machine.

sshd ... démon ssh
Lance un service ssh

scp ... copie sécurisé vers/à partir d'une machine distante
Les fichiers sont copiés via une session ssh encryptée

sftp ... version sécurisée de FTP
La session ftp est lancée dans une session ssh encryptée

openssl ... gère les certificats TLS/SSL

certtool ... crée de nouvelles paires de clés pour les certificats

rcp ... copie distante de fichiers
Copie des fichiers vers/à partir d'hôte distante qui exécute un serveur rlogin server. Remplacé par 'scp'.

rlogin ... connexion sur une machine distante
La machine distante doit exécuter un serveur rlogin. Remplacé par 'ssh'

rsh ... exécute un shell sur une machine distante
Remplacé par 'ssh'

rexec ... exécution à distance
Remplacé par 'ssh'

pine ... client email en ligne de commande


Commandes Diverses

Les trois dernières semaines et celle en cours constitueront une référence des commandes Unix en listant de nombreuses commandes par type d'usage spécifique. Il y a tant de commandes disponibles qu'il serait impossible de toute les connaître ou même de se rappeler de celles que l'on a utilisées le mois dernier.

Reportez-vous au reste des astuces pour avoir de nombreux exemples d'utilisation de ces commandes.

Et bien sûr, n'oubliez pas de consulter le manuel Unix 'man'.

Pour régler et afficher des variables d'environnement ou du shell. Les commandes sont marquées en tant que (tcsh) et en tant que (bash) si elles sont compatibles avec ces shells respectifs, et en tant que (Unix) si elles sont des commandes Unix standards.

set ... régle une variable shell (tcsh)
set ... règle des options shell (bash)
unset ... supprime une variable shell (tcsh et bash)
setenv ... règle une variable d'environment (tcsh)
unsetenv ... supprime une variable d'environment (tcsh)
env ... règle et affiche l'environment (Unix)
printenv ... affiche les variables d'environment (tsch et Unix)
(Voir la semaine 54)

Ces commandes sont utiles dans les scripts shell.

expr ... évalue une expression
L'expression peut être arithmetique, relationelle ou logique
Utilisée dans les scripts sous la forme `expr ...` ou $(expr ...)
$ a=$(expr 1 + 1 )
$ echo $a
(Voir semaine 54 - Vendredi)

getopt ... récupère et analyse les options de la ligne de commade
C'est l'utilitaire standard d'analyse de la ligne de commande utilisé par beaucoup de commandes pour traiter les options et les arguments de la ligne de commande.

mktemp ... génère des noms de fichier uniques et termporaires
Option -d pour faire un répertoire
Option -t pour inclure un préfixe

printf ... impression formattée à affficher
Voir 'man 3 printf' pour plus de détails sur la chaîne de formattage.
(Voir les semaines 27, 65 et 86)

sleep ... interrompt le traitement d'un script
Le script est en pause pendant le nombre donnée de secondes pour permettre à d'autres traitements de s'exécuter

[ et test ... teste une expression et retourne 0 (TRUE) ou 1 (FALSE)
Utilisé dans des instructions conditionelles telles que 'if' et 'while'
(Voir semaine 82)

xargs ...
Option -0 pour s'attendre à des noms de fichier séparés par null. Utilisé avec 'find -print0' pour supporter les noms de fichiers comportant des espaces
Option -n pour limiter le nombre d'arguments de chaque invocation. Utilisé si la ligne de commande générée est trop longue (comporte trop d'arguments).
(Voir les semaines 49, 98 Jeudi)

lockfile ... empêche un fichier d'être accédé par plus d'un process

Ces commandes compressent des fichiers et constituent des archives.

zip unzip ... compresse/décompresse des fichiers et des dossiers
gzip gunzip ... version GNU de zip
bzip2 bunzip2 ... utilise un algorithme meilleur de compression
Option -1 à -9 pour ajuster le niveau de la compression,
-1 est plus rapide mais compresse le moins
(Voir semaines 5 Vendredi, 37, 75 Mardi)

tar ... archive des fichiers en un seul
Option -c pour créer une nouvelle archive
Option -x pour extraire à partir d'une archive existante
Option -r/-A pour ajouter des fichiers à une archive existante
Option -z pour (dé)compresser avec gzip

Commandes diverses.

visudo ... édition sûre de /etc/sudoers
'sudoers' ne devrait normallement pas être édité par un éditeur de texte standard. visudo bloque le fichier et éffectue des vérifications de bon sens.
(Voir semaine 36)

vipw ... édition sûre de /etc/passwd
'passwd' ne devrait normallement pas être édité par un éditeur de texte standard. vipw bloque le fichier et éffectue des vérifications de bon sens.
Cette commande est redondante étant donné que OS X utilise des mot de passes ombrés et donc n'utilise pas /etc/passwd à part en mode utilisateur simple.

time ... chronomètre le temps d'exécution d'une commande

limit/unlimit ... change les limites d'une ressource système


Spécial OS X - Commandes pour Disques et Fichiers

Ces commandes sont spécifiques à OS X et ne sont pas disponibles dans d'autres variétés d'Unix.
(Voir semaine 16 et 18)

Manipulation et maintenance de disques.

disktool ... rafraîchit, éjecte, monte ou démonte
(Voir semaine 22)

diskutil ... répare, journalise des disques
(Voir semaine 88)

drutil ... interagit avec les graveurs de CD et de DVD

hdiutil ... manipule les images disque
(Voir les exemples d'usage dans l'astuce de Vendredi)

cd9660.util ... monte des volumes ISO 9660

udf.util ... monte des volumes DVD
ufs.util ... monte des volumes UFS (Unix File System)
hfs.util ... monte volumes HFS (Standard Apple)

pdisk ... éditeur de table de partition
Liste toutes les partitions des disques montés avec :
sudo pdisk
Top level command (? for help): L

vsdbutil ... active les permissions de lecture/écriture sur les volumes HFS+

ditto ... copie des fichiers/synchornise des dossiers avec leurs resource forks
Option -rsrc pour copier en préservant les resource forks

cpMac ... copie avec les resource forks
Copie les resource forks comme ditto. Inclus dans les Outils Développeurs et non inclus dans une installation standard.

GetFileInfo ... obtient les attributs de fichiers HFS+

SetFile ... règle les attributes de fichiers HFS+
Règle les attributs HFS+ tels que Alias, Locked, Invisible


Spécial OS X - Commandes Système

Voici des lignes de commandes équivallentes à des panneaux de préférences système.
(Voir semaine 16 et 18)

softwareupdate ... version ligne de commande de Màj Logiciel
Cela est utile pour une mise à jour des logiciels via une connexion distante sur un serveur.

update_prebinding ...
redo_prebinding ...
Lorsque de nouveaux exécutables et de nouvelles librairies sont ajoutés, ces commandes peuvent être utilisées pour mettre à jour les informations de laison de façon à ce que les commandes soient lancées plus rapidement. Normalement effectué lors d'une installation ou mise à jour de logiciels.

system_profiler ... génére des informations système détaillées
C'est une ligne de commande équivalente à 'À propos de ce Mac' du menu Pomme. Elle génére des informations textuelles vers la sortie standard.

scselect ... change la configuration réseau
Ceci est équivalent au changement effectué dans le panneau Réseau des Préférences Système

pmset ... règle les paramètres de gestion d'énergie (écran, disque, etc)

bless ...consacre un dossier système, le rend optionnellement disque de démarrage
Peut être utilisé pour changer le disque de démarrage et pour 'enregister' des systèmes clonés.
(Voir semaine 75)

nvram ... manipulation des variables Open Firmware NVRAM
(Voir semaine 75)

ioreg ... affiche la hiérarchie IO reg

service ... interface vers les services xinetd - script shell

Ces commandes interroge et manipule des informations dans les Services NetInfo et Directory.
(Voir semaines 91 et 96 pour les scripts qui utilisent les commandes des Services NetInfo et Directory.)

DirectoryService ... démon DS, fait partie de Open Directory

ni* ... ensemble de commandes NetInfo pour interroger et changer NetInfo
(Voir exemple d'utilisation dans l'astuce de Vendredi)
nicl ... NetInfo Command Line Utility
nidump ... déverse des informations NetInfo au format FF Unix
niload ... charge des informations NetInfo au format FF Unix
niutil ... lit et écrit un domaine au format texte
nifind ... cherche un répertoire NetInfo
nigrep ... effectue une recherche en expression régulière sur NetInfo
nireport ... affiche des tableaux à partir de NetInfo

dscl ... utilitaire en ligne de commande des services de répertoire
dscl est préféré aux commandes ni*
(Voir exemple d'utilisation dans l'astuce de Vendredi)

scutil ... interface vers configd pour gérer les emplacements réseau etc


Spécial OS X - Commandes Utilitaires

open ... ouvre un fichier comme s'il avait été double-cliqué
(Voir semaine 67)

screencapture ... copie d'écran et de fenêtre
(Voir exemple d'utilisation dans l'astuce de Vendredi)

Ces commandes ont pour but la maintenance et la vérification des fichiers de préférences de Mac OS X (ceux qui se terminent par .plist dans les dossiers de préférences).

defaults ... lecture et écriture de fichiers .plist
plutil ... .utilitaires plist
(Voir les semaines 88 et 100)

Commandes diverses.

say ... convertisseur de texte en paroles

sips ... système scriptable de traitement des images

appleping ... envoie un ping sur un réseau appletalk

certtool ... gère les certificats TLS/SSL et les accès au trousseau
(Voir 'man openssl')

opendiff ... ouvre deux fichiers et les compare

lsbom ... interprête le contenu de fichiers binaires bom
Voir 'man 5 bom'

otool ... examine des fichiers objet (=Unix ldd)


Exemple d'Utilisation

Ces exemples sont tirés de mes propres notes et n'ont pas été testé un seul moment.

Commande de Capture d'Écran

Lorsque vous utilisez la version interactive (commande-majuscule-4), la barre d'espace passe du mode régulier de sélection à un nouveau mode qui ne capture qu'une seule fenêtre, le Dock ou la barre de menus. Le curseur se transforme en un appareil photo lorsque vous passez dans ce mode et, au passage de la souris, différentes régions de l'écran sont mises en évidence.

Les captures d'écran peuvent être provoquées à partir de la lligne de commande (et par conséquent à partir d'AppleScript, de perl, etc...) en utilisant la nouvelle commande de capture d'écran située dans /usr/sbin/

utilisation : screencapture [-icmwsWx] [file] [cursor]
-i capture l'écran de manière interactive, par sélection ou par fenêtre
touche contrôle - provoque l'envoi de la capture vers le presse-papier
touche espace - bascule entre les modes sélection à la souris et sélection de fenêtre
touche escape - annule la capture interactive
-c force la capture d'écran à aller vers le presse-papier
-m ne capture que le moniteur principal, ne fait rien si -i est positionné
-w ne permet que le mode de sélection de fenêtre
-s ne permet que le mode de sélection à la souris
-W démarre l'interaction en mode sélection de fenêtre
-x ne joue pas de son
file indique où enregistrer la capture d'écran

Commande hdiutil

Voici comment créer une image disque de 50Mo, y sauvegarder des données puis la graver sur CD (directement à partir de la ligne de commande).

hdiutil create -fs HFS+ -volname Backup -size 50m ~/Desktop/backup.dmg
hdiutil mount ~/Desktop/backup.dmg
ditto -rsrc -V ~/Desktop/datatobackup /Volumes/Backup >> /Volumes/Backup/backup.log
hdiutil unmount /Volumes/Backup
hdiutil burn ~/Desktop/backup.dmg -noverifyburn -noeject

Ensemble de Commandes NetInfo

- Sauvegarde une base de données NetInfo
nidump -r / -t localhost/local > backup.nidump

- Restaure une base de données NetInfo à partir d'une sauvegarde
periodic daily backs-up the NI database to /var/backups/local.nidump

En mode utilisateur simple avec / monté, déplace l'ancienne /var/db/netinfo/local.nidb
Démarre les services essentiels
/usr/libexec/kextd
/usr/sbin/configd
/sbin/SystemStarter

Crée une base de données NetInfo vierge et démarre NetInfo
/usr/libexec/create_nidb
/usr/sbin/netinfod -s local

Charge la sauvegarde dans NetInfo:
/usr/bin/niload -d -r / . < /var/backups/local.nidump

- Re-crée NetInfo via le tout premier réglage d'OS X
rm /var/db/.AppleSetupDone
reboot

Autres Commandes

bless
Positionne OS X comme système de démarrage
sudo bless -folder '/System/Library/CoreServices' -setOF
Positionne OS 9 comme système de démarrage
sudo bless -folder9 '/Volumes/Mac OS 9/System Folder' -setOF

defaults
defaults read/write/delete
defaults write com.apple.terminal TerminalOpaqueness '0.85';

fsck
En mode utilisateur simple, pour réparer la partition 5 du disque HFS 1
fsck_hfs -y /dev/rdisk1s5

man
man 7 ascii ... table ASCII
man 7 hier ... hiérarchie du système de fichiers
man cmd | col -b ... affiche les pages du manuel

mount
mount_afp [-o option1[,option2 ...]] afp://[username:password]@rhost[:port]/volume node

mount_cd9660 /dev/disk2s1 /Volumes/cd
umount /Volumes/cd

mount -t hfs -w /dev/disk0s10 /Volumes/Grima

nvram
nvram -p ... pour afficher des variables
sudo nvram boot-args="-v" ... passe en mode "verbeux" lors du démarrage

tcpflow
sudo tcpflow -i en1 -c port 80

whois
whois -h whois.arin.net ip-address


Information d'Arrière-plan

Bash peut être lancé en tant que shell de connexion ou en tant que shell classique. Une des différences les plus significatives entre les deux modes tient dans les scripts d'initialisation lancés lorsque Bash démarre.

Un shell de connexion ira puiser les scripts de connexion suivants :

  /etc/profile
  ~/.bash_profile

(Si ~/.bash_profile ne peut être lu, ~/.bash_login est engagé, et si celui-ci ne peut être lu, alors on fait appel à ~/.profile)

Au moment de la déconnexion, un shell de connexion fait appel à ~/.bash_logout.

Un shell classique fait appel aux scripts suivants :

  /etc/bashrc
  ~/.bashrc

NOTE : d'après le manuel de Bash, /etc/bashrc n'est pas appelé, mais il l'est.

Lorsque le Terminal d'Apple démarre une nouvelle session, il lance un shell Bash de connexion. Quand le xterm de X11 démarre une nouvelle session, il lancé un shell Bash classique.

Lorsque vous tapez 'bash' à la ligne de commande, un shell classique est lancé.

Shells non-interactifs. Lorsque vous lancez un script shell, un nouveau shell est lancé pour exécuter le script. Le nouveau shell est un shell non-interactif. Il ne fait appel à aucun script au démarrage.

Un shell classique est quitté par 'exit', et un shell de connexion par 'logout'. Le fait de taper 'exit' dans un shell de conexion lancera 'logout'.


Lancer des Shells de Connexion avec X11 Xterm

Dans l'astuce de Lundi, on peut s'apercevoir que le Terminal d'Apple lance un shell de connexion tandis que le X11 xterm lance un shell classique. Pour aider à rationaliser ce comportement et obtenir un environnement uniforme, nous pouvons changer X11 xterm pour qu'il lance un shell de login.

Faites en sorte que X11 lance des shells de connexion. Editez /etc/X11/xinit/xinitrc et changez la ligne qui invoque xterm :

xterm &

en :

xterm -ls &

Autrement, pour n'affecter que votre propre compte utilisateur, créez un fichier ~/.xinitrc qui sera une copie de /etc/X11/xinit/xinitrc, et effectuez la même modification.

Maintenant X11 lance un shell de connexion.

Encore mieux. Pour être sûr que toutes les fenêtres xterm soient aussi des shells de connexion, au lieu de faire ce que l'on a vu ci-dessus créez un fichier appelé ~/.Xdefaults

$ cat ~/.Xdefaults
# Default settings for X Applications
#

# xterm
XTerm*.LoginShell: True

Maintenant, xterm lancera un shell de connexion qu'il soit invoqué par X11 au démarrage, qu'il soit lancé par la ligne de commande 'xterm &' ou par le menu Applications de X11.

Personnalisez le look d'un terminal xterm en ajoutant plus de lignes dans ~/.Xdefaults. Par exemple :

XTerm*background: black
XTerm*foreground: white
XTerm*backdrop: white
XTerm*rightScrollBar: True
XTerm*ScrollBar: True
xterm*saveLines: 5000
XTerm*VT100*geometry: 100x55+10+10

(La raison pour laquelle X11 lance des shells classiques est que dans la plupart des systèmes Unix X11 contrôle la fenêtre 'root' et qu'un environnement correct a déjà été mis en place. Sous Mac OS X, Aqua contrôle la fenêtre root. Ainsi il est préférable que xterm lance des shells de connexion de façon à ce qu'ils puisent dans les scripts de connexion.)


Scripts d'Initialisation

Les quatre différents scripts d'initialisation (voir l'astuce de Lundi) doivent être réglés correctement pour être sûr que les shells disposeront d'un environnement correct.

Tout d'abord, /etc/profile et /etc/bashrc agissent au niveau système. Utilisez ces scripts pour mettre en place l'environnement commun à tous les utilisateurs. ~/.bash_profile et ~/.bashrc sont spécifiques à chaque utilisateur et sont utilisés pour ajouter des options personnelles à l'environnement.

Ensuite, /etc/profile et ~/.bash_profile sont lus par les shells de connexion et donc appliqués une fois par session terminal. Le fait de taper 'bash' à la ligne de commande lance un shell classique qui ira lire /etc/bashrc et ~/.bashrc.

Une bonne stratégie consiste à faire ce qui suit :

Utilisez /etc/profile et ~/.bash_profile pour régler les variables d'environnement. Elles sont héritées par les shells classiques et ne nécessitent pas d'être positionnées de nouveau.

Utilisez /etc/bashrc et ~/.bashrc pour mettre en place des variables shell et autres réglages shell. Ces variables ne sont pas héritées par les shells classiques et donc nécessitent d'être positionnées à chaque fois.

Enfin, /etc/profile devrait lire /etc/bashrc :

source /etc/bashrc

and ~/.bash_profile should source ~/.bashrc:

source ~/.bashrc

pour éviter d'avoir à positionner les variables shell à la fois dans les scripts de connexion et les scripts classiques. Notez qu'ils doivent être "puisés" et pas simplement appelés comme suit :

/etc/bashrc

Éviter l'Exécution des Scripts d'Initialisation

Pour éviter que bash n'exécute /etc/profile et ~/.bash_profile lorsqu'il est invoqué en shell de connexion, utilisez :

bash --noprofile

Pour éviter qu'un shell classique n'exécute /etc/bashrc et ~/.bashrc, lancez le à la ligne de commande comme suit :

bash --norc

Pour créer un shell de connexion à la ligne de commande, utilisez :

bash --login

Pour avoir l'option 'noprofile' dans X11, utilisez Applications::Customise... de la barre de menus de X11 pour ajouter un nouvel élément. Donnez lui un nom dans le style "xterm-np" et tapez la commande :

/usr/X11R6/bin/xterm -e /bin/bash --noprofile

Notez que nous indiquons à xterm de lancer une commande avec l'option -e. Si aucune option n'est passée, bash est lancé avec ses paramètres par défaut.

Fink. Attention ! Si vous exécutez le script d'initialisation de Fink, par exemple :

[ -r /sw/bin/init.sh ]&& source /sw/bin/init.sh

le script vérifie que '/sw/bin' et '/sw/sbin' sont présents dans le chemin d'accès. Si ce n'est pas le cas, ajoutez les au début du chemin d'accès. Fink comprend une version de bash qui ne lit pas /etc/profile mais qui lit /sw/etc/profile. Cela peut rendre le choses confuses si vous lancez un shell de connexion en tapant 'bash --login'. Pour éviter tout pronlème, ajoutez '/sw/bin' et '/sw/sbin' à la fin de votre chemin d'accès avant d'appeler '/sw/bin/init.sh', ou sinon faites un alias vers le bash correct ou invoquez le directement avec '/bin/bash'


Script vs 'source' vs '.'

L'exécution d'un script sous une forme usuelle à la ligne de commande :

$ name-of-script

lance le script dans un nouveau shell bash. Si vous voulez qu'un script soit exécuté par le shell courant, vous devez l'appeler avec 'source' :

$ source name-of-script

ou

$ . name-of-script

L'exécution d'un script d'initialisation comme /etc/bashrc au lieu de le "sourcer" ne marchera pas. Lorsque le nouveau shell se termine, tout son environnement et toutes ses variables shell sont détruites.

Si vous devez garder trace des scripts d'initialisation qui ont été lancé dans un environnement shell, utilisez la technique suivante :

Pour /etc/profile ajoutez :

declare -x STARTUP="/etc/profile, "

Pour /etc/bashrc ajoutez:

declare -x STARTUP="${STARTUP}/etc/bashrc, "

et de même pour ~/.bash_profile ajoutez:

STARTUP="${STARTUP}~/.bash_profile, "

et pour ~/.bashrc ajoutez:

STARTUP="${STARTUP}~/.bashrc, "

Tout autre fichiers "sourcés" tels que ceux de Fink doivent aussi avoir des instructions similaires ajoutées.


De Zcat à Gzcat

Dans les versions de Mac OS X antérieures à la 10.4 (Tiger), la commande zcat, comme d'autres commandes z, faisait partie du package d'outils de compression GNU. Elle pouvait être utilisée pour directement afficher le contenu de fichiers compressés avec gzip.

De tout temps, zcat servait à afficher des fichiers compressés par la commande Unix compress (l'extension utilisé pour ce type de fichier est .Z). La commande était souvent remplacée par la version GNU.

Dans Tiger, le zcat original a été préservé mais la version GNU est appelée gzcat. Aussi, utilisez toujours gzcat tant que le fichier n'a pas été compressé avec la commande compress.

$ zcat /var/log/system.log.0.gz
zcat: /var/log/system.log.0.gz.Z: No such file or directory
$ zcat /var/log/system.log.0
zcat: /var/log/system.log.0.Z: No such file or directory
$ gzcat /var/log/system.log.0.gz
...
Jan  1 18:11:36 Sauron kernel[0]: AFP_VFS afpfs_mount: ...
Jan  1 18:11:49 Sauron kernel[0]: AFP_VFS afpfs_unmount: ...
...

Notez que dans les systèmes pré-Tiger, gzcat était installé en tant que zcat et aussi en tant que gzcat. Utilisez gzcat dans les scripts par souci de portabilité.

Voici un rappel des nombreuses variantes de commandes z disponibles :

zcat     zdiff    zfgrep   zgrep   zmore    zprint
zcmp     zegrep   zforce   zless   znew

Notez que znew peut être utilisé pour recompresser des fichiers .Z en fichier .gz. Aussi inclus, le très utile zless, qui manquait dans les versions précédentes de Mac OS X.

Rappelez vous aussi que les fichiers compressés par bzip2 sont rattachés à un ensemble d'utilitaires.

bzcat   bzdiff   bzfgrep   bzip2        bzless
bzcmp   bzegrep  bzgrep    bzip2recover bzmore

Rendez-vous sur le Site du livre des astuces Unix :
Le Projet 22 couvre la commande gzcat.
Le Projet 27 montre comment compresser des fichiers.


Pico devient Nano

L'éditeur pico a toujours était très populaire et facile pour apprendre un éditeur de texte Unix. Il faisait partie du package PINE et en tant que tel soufrait de quelques limitations dont l'absence de rechercher / remplacer. Il a été remplacé par l'éditeur GNU nano. Nano est compatible avec pico, mais il offre des fonctions en plus.

Le site officiel de nano, ww.nano-editor.org, comporte de nombreuses ressources utiles pour les utilisateurs de nano. Le plus important pour les utilisateurs de versions antèrieures à Mac OS X 10.4, qui ne comprennent pas nano, est la possibilité de télécharger gratuitement le programme. Voici les instructions pour l'installer :

Téléchargez le source en cliquant sur le lien situé en bas de l'écran intitulé Get Nano, puis en cliquant sur le ficher nano-[numéro-de-version].tar.gz. Le programme se construit facilement dans Panther. Tapez les instructions suivantes dans une fenêtre Terminal (le numéro de verson peut différer de celui indiqué ici) :

$ tar xzf nano-1.2.5.tar.gz
$ cd nano-1.2.5/
$ ./configure
  # ...much output here....
$ make
$ sudo make install
Password:
  # ...output here...

L'exécutable sera installé dans /usr/local/bin/nano, et la page du manuel dans /usr/local/man/. Si /usr/local/bin n'est pas votre chemin de recherche, vous aurez besoin soit de l'ajouter soit d'invoquer nano en utilisant son chemin d'accès complet.


Syntaxe Colorée dans Nano

Nano est capable de colorer la syntaxe. Par exemple, nous pouvons lui dire d'afficher les balises HTML telles que en bleu, et les caractères d'échappement tels que & en rouge. Saisissez le texte suivant dans le fichier nanorc, appelé .nanorc dans votre répertoire de départ.

#HTML Syntax Highlighting
syntax "HTML" ".html$"
color blue start="<" end=">"
color red "&[^;       ]*;"

La seconde ligne indique que la syntaxe HTML est appliquée à tous les fichiers dont le nom se termine par .html. La troisième indique que tout ce qui se trouve entre < et > (éventuellement sur plusieurs lignes) doit être coloré en bleu, et la quatrième ligne indique que tout ce qui se trouve entre & et ; (lorsqu'il n'y a pas d'espace ou de virgule à l'intérieur) doit être coloré en rouge. (Le texte entre [ et ] comprend aussi un caractère espace et un caractère tabulation).

Vous pouvez spécifier chacune des couleurs suivantes : white, black, red, blue, green, yellow, magenta, cyan ; et préfixer chacune avec le mot 'bright'. La chaîne sur laquelle devra s'appliquer la couleur est spécifiée en utilisant une expression régulière.

Essayez de charger un fichier HTML dans une nouvelle instance de nano, tel que ~/Sites/index.html, et vous devriez voir la colorisation de la syntaxe telle que décrite précédemment.

Téléchargez les fichiers source de nano (voir l'astuce d'hier) et vous trouverez un fichier appelé nanorc.sample. Ce fichier donne des exemples de ce qui peut être placé dans le fichier de configuration, et comment écrire des instructions de mise en évidence de la syntaxe.


Encore Plus de Commandes

Tiger comprend les commandes suivantes qui ne faisaient pas partie des précédentes versions de Mac OS X.

1) Le shell Korn dans /bin/ksh, utile si vous souhaitez lancer un script shell Korn (ou si vous préférez utiliser Korn comme shell interactif).

2) zless, partie de la boite à outils zip GNU, affiche le contenu de fichiers compressés à l'aide de la commande less. C'est réellement un script très simple :

$ cat /usr/bin/zless
#!/bin/sh
PATH="/usr/bin:$PATH"; export PATH
LESSOPEN="|gzip -cdfq %s"; export LESSOPEN
exec less "$@"
$

3) textutil, qui est une interface ligne de commande au système des textes Cocoa. Quelques exemples d'utilisation de textutil sont :

Pour convertir le fichier HTML index.html en Rich Text Format, et l'écrire dans index.rtf, tapez :

$ textutil -convert rtf index.html

Pour convertir le même fichier en un document MS Word, et l'écrire dans index.doc, tapez :

$ textutil -convert doc index.html

L'option -cat est pratique pour concaténer tous les fichiers en entrée en un gros fichier en sortie.

4) mdfind est une commande Spotlight. Elle cherche des valeurs d'attributs au travers de meta-données.

Pour plus de détails sur textutil et mdfind, consultez les pages man..

Voici une astuce pratique pour convertir une sortie postscript en PDF grace à Preview.app. Dans cet exemple, nous lions la page man de bash au format brut postfix à Preview.app.

$ man -t bash | open -f -a /Applications/Preview.app

Bien propre avec Tidy

Tidy (propre) est un utilitaire de vérification de syntaxe et de nettoyage de code source HTML. Tapez :

$ tidy -h

pour voir l'écran d'aide.

Consultez tidy sur sourceforge.

Tidy peut être installé sur des versions antérieures de Mac OS X à partir de sourceforge et probablement à partir d'autres portages comme Fink et DarwinPorts.

Si vous êtes dans l'éditeur vim, tidy peut être utilisé pour vérifier et nettoyer des fichiers source HTML directement dans vim. Ajoutez le type suivant de plugin pour les fichiers html :

$ cat ~/.vim/ftplugin/html/tidy.vim 
""""""""""""""""""""""""""""""""""""""""""""""
" Adrian's vim filetype plugin for html tags "
""""""""""""""""""""""""""""""""""""""""""""""
"
" Maintainer:  Adrian Maio
" URL:         http://www.mayo-family.com/vim/ftplugin/html/tidy.vim
" MAIN URL:    http://www.mayo-family.com/vim
"
" This file defines maps to call the html tidy program, see:
"   http://tidy.sourgeforge.net/
"
" This file should be placed in ~/.vim/ftplugin/html/ on Unix systems
"   and will automatically be sourced for filetype = html.
"

" Map to check html and display error in a new window " noremap err :1yG :20newp :setfiletype html :%!tidy -i >/dev/null
" Map to tidy html " noremap tidy :%!tidy -i -f /dev/null
" END "

Les nouvelles commandes sont appelées en tapant err et tidy en mode normal.