J'essaie d'automatiser la détection et l'élimination périodiques des fichiers à l'aide de fdupes. J'ai ce beau script:

# from here:
# https://www.techrepublic.com/blog/linux-and-open-source/how-to-remove-duplicate-files-without-wasting-time/

OUTF=rem-duplicates_2019-01.sh;

echo "#! /bin/sh" > $OUTF;

find "$@" -type f -printf "%s\n" | sort -n | uniq -d |
    xargs -I@@ -n1 find "$@" -type f -size @@c -exec md5sum {} \; |
    sort --key=1,32 | uniq -w 32 -d --all-repeated=separate |
    sed -r 's/^[0-9a-f]*( )*//;s/([^a-zA-Z0-9./_-])/\\\1/g;s/(.+)/#rm \1/;' >> $OUTF;
chmod a+x $OUTF; ls -l $OUTF

Cela produit un fichier avec cette structure:

#! /bin/sh
#rm ./directory_a/file_a
#rm ./directory_b/file_identical_to_a

#rm ./directory_a/file_b
#rm ./directory_b/file_identical_to_b
#rm ./directory_c/another_file_identical_to_b

#rm ./directory_a/file_c
#rm ./directory_b/file_identical_to_c
#rm ./directory_c/another_file_identical_to_c
#rm ./directory_d/yet_another_file_identical_to_c

Je souhaite supprimer la balise # de la première ligne de chaque paragraphe pour obtenir

rm ./directory_a/file_c
#rm ./directory_b/file_identical_to_c
#rm ./directory_c/another_file_identical_to_c
#rm ./directory_d/yet_another_file_identical_to_c

J'ai essayé de modifier l'avant-dernière ligne, avec des variantes de choses comme celle-ci:

    sed -r 's/^[0-9a-f]*( )*//;s/([^a-zA-Z0-9./_-])/\\\1/g;s/(.+)/#rm \1/;s/\n\n#rm/\n\nrm/;' >> $OUTF;

Mais je ne peux pas gérer SED pour reconnaître le (\ n \ n) ou tout autre pointeur auquel je peux penser au début du paragraphe. Qu'est-ce que je fais mal?

Edit: Je ne peux pas modifier le commentaire, voici donc le script final:

TEMPF=temp.txt;
OUTF=rem-duplic_2019-01.sh

echo "#! /bin/sh" > $TEMPF;

find "$@" -type f -printf "%s\n" | sort -n | uniq -d |
    xargs -I@@ -n1 find "$@" -type f -size @@c -exec md5sum {} \; |
    sort --key=1,32 | uniq -w 32 -d --all-repeated=separate |
    sed -r 's/^[0-9a-f]*( )*//;s/([^a-zA-Z0-9./_-])/\\\1/g;s/(.+)/#rm \1/' >> $TEMPF;
awk -v a=2 '/^$/{a=2}!--a{sub(/#/,"")}1' $TEMPF > $OUTF

chmod a+x $OUTF; ls -l $OUTF
rm $TEMPF
1
yozzarian 26 janv. 2019 à 22:12

5 réponses

Meilleure réponse

Utilisez plutôt awk:

awk '/^$/{a=1} !a--{sub(/#/,"")} 1' a=1 file
  • /^$/ { a = 1 } signifie mettre a à 1 si la ligne actuelle est vide,
  • !a-- est un raccourci pour a-- == 0, l'action suivante ({ sub(/#/, "") }) supprime le premier # de la ligne actuelle,
  • 1 signifie imprimer toutes les lignes,
  • a=1 est nécessaire pour supprimer # de la ligne après shebang (c.-à-d. 2e ligne).
0
oguz ismail 27 janv. 2019 à 08:10

Cela pourrait fonctionner pour vous (GNU sed):

sed '/^#!\|^\s*$/{n;s/.//}' file

Si la ligne courante est un shebang ou une ligne vide, imprimez-la et supprimez le premier caractère de la ligne suivante.

0
potong 27 janv. 2019 à 13:44

Utilisez simplement Perl avec le mode paragraphe

perl -00 -pe ' s/^#// ' 

Avec entrées

$ cat yozzarian.txt
#! /bin/sh
#rm ./directory_a/file_a
#rm ./directory_b/file_identical_to_a

#rm ./directory_a/file_b
#rm ./directory_b/file_identical_to_b
#rm ./directory_c/another_file_identical_to_b

#rm ./directory_a/file_c
#rm ./directory_b/file_identical_to_c
#rm ./directory_c/another_file_identical_to_c
#rm ./directory_d/yet_another_file_identical_to_c
$ perl -00 -pe ' s/^#// ' yozzarian.txt
! /bin/sh
#rm ./directory_a/file_a
#rm ./directory_b/file_identical_to_a

rm ./directory_a/file_b
#rm ./directory_b/file_identical_to_b
#rm ./directory_c/another_file_identical_to_b

rm ./directory_a/file_c
#rm ./directory_b/file_identical_to_c
#rm ./directory_c/another_file_identical_to_c
#rm ./directory_d/yet_another_file_identical_to_c
$
0
stack0114106 28 janv. 2019 à 11:41

Vous pouvez également l'utiliser:

sed '/^$\|^#!/{N;s/#r/r/}' input.txt

n'hésitez pas à ajouter l'option sur place si vous le souhaitez

0
Rafael 27 janv. 2019 à 02:53

Avec sed:

sed "1n;/^#/,/^$/{ s///;}" file
1
SLePort 27 janv. 2019 à 04:32