Parser les espaces du nom d'un fichier (sortie de find + sed + array)

Tags: #<Tag:0x00007f509fd91a60>

Bonjour,

J’essaie de récupérer une liste des fichiers modifiés (depuis X min) dans un répertoire.

Exemple (je vous laisse les options de la commande find pour information personnelle :

find "/home/USER/" ! -path "/home/USER/ignore/*" -type f \( -iname "*" -or -iname ".*" ! -iname ".afileignore" \) -mmin -60 -exec ls -lh {} \; | awk '{print $9":"$5}')

Qui me ressort :

/home/USER/my_file.txt:85K
/home/USER/my_file_second.txt:195K

Par contre si j’ai un fichier qui contient des espaces çà bug.

Exemple : « /home/USER/my_file_avec espace.txt » ; ma commande find ne fonctionne pas , elle me retourne :

/home/USER/my_file_avec

Qui a une solution ?

Je souhaite garder la taille des fichiers.

Merci.

Bonne journée.

Romain.


Note de Moi-même :

TEST
root@lb2.ww2:~ $ find /var/pro/web_public/ -mmin -1200 -exec ls -lh {} \;
total 679M
-rw-r--r-- 1 1000 1000   17K Feb  5  2024 "Capture d'écran 2024-02-05 195622.png"

root@lb2.ww2:~ $ find /var/pro/web_public/ -mmin -1200 -exec ls -lh {} \; | sed -f /root/url_escape.sed
total%20679M
-rw-r--r--%201%201000%201000%20%20%2017K%20Feb%20%205%20%202024%20Capture%20d'écran%202024-02-05%20195622.png

le fichier : « cat url_escape.sed » : CF.

# sed url escaping
s:%:%25:g
s: :%20:g
s:<:%3C:g
s:>:%3E:g
s:#:%23:g
s:{:%7B:g
s:}:%7D:g
s:|:%7C:g
s:\\:%5C:g
s:\^:%5E:g
s:~:%7E:g
s:\[:%5B:g
s:\]:%5D:g
s:`:%60:g
s:;:%3B:g
s:/:%2F:g
s:?:%3F:g
s^:^%3A^g
s:@:%40:g
s:=:%3D:g
s:&:%26:g
s:\$:%24:g
s:\!:%21:g
s:\*:%2A:g

C’n’est pas encore çà. Je cherche…

Je crois bien que j’ai réussis :

root@lb2.ww2:~ # ls -lhQ
total 264K
-rw-r--r-- 1 root root  17K Oct 16 08:16 "Capture d'écran 2024-02-05 195622.png"
-rw-r--r-- 1 root root  46K Oct 16 08:16 "Capture d'écran 2024-02-05 195739.png"
-rw-r--r-- 1 root root  40K Oct 16 08:16 "Capture d'écran 2024-02-05 200425.png"
-rw-r--r-- 1 root root  21K Oct 16 08:16 "Capture d'écran 2024-02-05 235747.png"
-rw-r--r-- 1 root root  33K Oct 16 08:16 "Capture d'écran 2024-02-05 235843.png"

Je cherche le 9ème champ « le titre » et le 5ème champ le « poid » :wink:

find . -maxdepth 1 -name "*.png" -exec ls -lhQ {} ';' | sed -r 's/(.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]]"([^"]+)"$/\9:\5/g'

OK çà me retourne les noms entier des fichiers et j’ajoute le poid :

./Capture d'écran 2024-02-05 195622.png:17K
./Capture d'écran 2024-02-05 195739.png:46K
./Capture d'écran 2024-02-05 235843.png:33K
./Capture d'écran 2024-02-05 235747.png:21K
./Capture d'écran 2024-02-05 200425.png:40K

J’ai ajouté l’option (-Q, --quote-name enclose entry names in double quotes) de la commande ls

Puis j’ai parsé tout les champs entre les espaces.
Puis je vérifie dès que je tombe sur une double quote, je récupère tous les caractères tant que ce n’est pas une double quote "([^"]+)" et dollar de fin de ligne.

Si vous avez de meilleur solution, je suis preneur.

:wink:


J’ai un autre problème ; c’est sur mon « array » bash. je n’arrive pas à le créer, qui a une soluce ? merci !

root@lb2.ww2:~ $ search=$(find /root/ -type f -name "*.png" -mmin -600 -exec ls -lhQ {} ';' |sed -r 's/(.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]]"([^"]+)"$/"\9:\5"/g') ; \
echo ""; \
IFS=""; array=(${search}) ; \
count=$(echo ${#array[@]}); \
echo "$count dans array"; \
for file in "${array[@]}"; do echo "-> $file"; done;

Me retourne :


1 dans array
-> "/root/Capture d'écran 2024-02-05 195622.png:17K"
"/root/Capture d'écran 2024-02-05 195739.png:46K"
"/root/Capture d'écran 2024-02-05 235843.png:33K"
"/root/Capture d'écran 2024-02-05 235747.png:21K"
"/root/Capture d'écran 2024-02-05 200425.png:40K"
root@lb2.ww2:~ #

j’ai essayé d’ajouter un retour ligne, ou nouvelle ligne et une tabulation à la sortie de la commande « sed » mais çà ne fonctionne pas non plus.

sed -r '/XXX/"\9:\5\r"/g'

:confused:

Bonjour @ZW3B,

Il aurait été préférable de séparer votre réponse de votre nouveau besoin par un nouveau message.

Pour répondre à votre problème, je vous invite dans un premier temps à remplacer array=(${search}) par array=("fichier1.txt" "fichier2.txt" "fichier3.txt")pour faire la part des choses.
Vous identifierez ainsi la ligne à la source du problème. Il y a fort à parier que ce soit la première.

Dans un deuxième temps remplacez, « file1.txt » par « /root/Capture d’écran 2024-02-05 195622.png:17K »

Progressivement vous identifierez de façon de plus en plus précise l’origine du ou des problèmes rencontrés.

3 J'aime

Bonjour, et merci pour la réponse @vbreton monsieur. En créant le tableau à la main çà fonctionne l’array.

C’est la sortie du « find » ; le « sed » qui met « tout sur une ligne » (pourtant il y a bien des espaces entre chaque « fichier » entre double-quotes et/ou des sauts de lignes.

On dirait que « sed » ne veut pas créait de tableau.

J’ai trouvé tout va bien …
J’ai entouré la déclaration du tableau array="(${search})"
Et j’ai envoyé declare -a pour déclarer le tableau proprement.

# search=$(find /root/ -type f -name "*.png" -mmin -600 -exec ls -lhQ {} ';' |sed -r 's/(.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]](.*)[[:space:]]"([^"]+)"$/"\9:\5"/g') ; \
echo ""; \
IFS=""; \
declare -a array="(${search})" ; \
count=$(echo ${#array[@]}); \
echo "$count dans array"; \
for file in "${array[@]}"; do echo "-> $file"; done;

5 dans array
-> /root/Capture d'écran 2024-02-05 195622.png:17K
-> /root/Capture d'écran 2024-02-05 195739.png:46K
-> /root/Capture d'écran 2024-02-05 235843.png:33K
-> /root/Capture d'écran 2024-02-05 235747.png:21K
-> /root/Capture d'écran 2024-02-05 200425.png:40K
root@lb2.ww2:~ #

Bonne journée.

Bien que awk aurait été plus judicieux que sed dans cet exemple, il y a quand-même plus direct… et beaucoup moins tordu:

find <options> -type f -exec du -h '{}' \;

Pour l’array, l’astuce pour conserver les espaces de nom de fichier est d’utiliser
-print0 | xargs -0
« for file in "${array[@]}; do » comprendra que le séparateur est un ‹ null › character, et non un espace ou retour de ligne.
voir man find → Safer ’find -print0 | xargs -0’ approach

Je n’ai pas tout compris mais je regarderais çà. Merci @verner.

Le problème des noms à espace est un grand classique avec find.
« find -print0 » sortira une ligne type ‹ fichier1fichier2fichier3 › qui parait illisible puisque fichier1 et fichier2 sont séparés par un caractère invisible qui sera parfaitement compris par xargs -0.

man xargs
-0, --null :
Input items are terminated by a null character instead of by whitespace

Comme le séparateur est invisible, il faut voir pour le croire…

ps: quel drôle d’idée ce type de nom de fichier à espaces: « Capture d’écran 2024-02-05 195739.png »
« Capture_écran_2024-02-05_195739.png » est quand-même plus judicieux.

On fait des image (capture d’écran) pour les partager sur lle web ; (c’est depuis mon poste windows l’imprime écran et (aussi) vidéo dans win11 c’est fun pour enregistrer rapidement le bureau).

Ouais il faut que je vois çà – comme je le disais.

Merci @verner !