J'ai une string multiligne dans la variable $PAT
. $PAT
doit être recherché dans le file $FILE
. Si $PAT
est dans $FILE
, il doit imprimer le file avec $PAT
supprimé. Si $PAT
n'est pas trouvé, n'imprimez rien. On ne sait pas si $PAT
contient des caractères spéciaux, et il doit correspondre littéralement. Par exemple, si $PAT
est //\/\\|*
alors la même string de 8 caractères doit être recherchée dans $FILE
.
Le monde réel utilise pour cela l'installation et la suppression de text dans des files / scripts déjà existants. Si vous voulez append $PAT
dans $FILE
, vous voulez savoir s'il a déjà été ajouté précédemment. Si $PAT
est déjà dans $FILE
, alors la sortie sans $PAT
vous permet de le désinstaller facilement.
Les systèmes dont j'ai besoin d'un tel script pour les appareils Android ne disposent que de BusyBox. Pas de Perl ou d'autres langages de script.
Je suppose que vous réécrivez un file text qui tient dans la memory (on dirait que vous réécrivez un file de configuration).
Le script suivant utilise uniquement les fonctionnalités shell embeddedes et cat
. Il devrait fonctionner sur la coquille d'Android, du less depuis Gingerbread et certainement depuis Ice Cream Sandwich. Il imprime le contenu du file less la première occurrence de $PAT
s'il y en a un; si $PAT
ne se produit pas, il n'imprime rien.
contents=$(cat "$FILE") case $contents in *"$PAT"*) echo "${contents%%$PAT*}${contents#*$PAT}";; esac
Cet extrait de code suppose que le file ne contient aucun octet nul, se termine par une seule nouvelle ligne et ne commence pas par un tiret. En outre, si le motif se termine par une nouvelle ligne, il ne sera pas trouvé à la fin du file. L'extrait de code plus complexe suivant gère les files text arbitraires:
contents=$(cat "$FILE"; echo a) contents=${contents%a} case $contents in *"$PAT"*) contents="${contents%%$PAT*}${contents#*$PAT}" dashes=${contents%%[!-]*} echo -n "$dashes" echo -n "${contents#$dashes}";; esac
(Notez que votre comportement proposé rend impossible de distinguer un file contenant exactement le model et un file vide.)
Il est en fait plus facile de mettre en œuvre votre script append / remove directement que d'utiliser la fonction intermédiaire proposée.
contents=$(cat "$FILE"; echo a) contents=${contents%a} append= case $contents in *"$PAT"*) contents="${contents%%$PAT*}${contents#*$PAT}";; *) contents="$contents$PAT" esac dashes=${contents%%[!-]*} { echo -n "$dashes"; echo -n "${contents#$dashes}"; } >"$FILE.new" mv -- "$FILE.new" "$FILE"
Si vous voulez faire correspondre $PAT
tant que lignes complètes, j'ai une solution. Par lignes complètes, je veux dire que, dans le cas d'une correspondance, vous pouvez split $FILE
en trois sous-files (f1, f2 & f3) où:
cat f1 f2 f3
est $FILE
, $PAT
. Notez que f1 et / ou f3 peuvent être vides.
Tout d'abord, créez le file f2:
cat << EOF > f2 $PAT EOF
Ensuite, diff $ FILE et f2, en enregistrant le résultat:
diff $FILE f2 > diff_res res=$?
Si $res
vaut zéro, alors f1 et f3 sont vides, et $ FILE est égal à $ PAT. Je suppose que vous voulez un file vide dans ce cas.
Si diff_res
contient une ligne commençant par " >
", f2 contient au less une ligne qui ne diff_res
pas dans $ FILE. Pour tester cela:
grep -q '^> ' diff_res test $? -eq 0 && echo "PAT not found"
Si diff_res
ne contient pas de lignes commençant par " >
", toutes les lignes de f2 sont dans $ FILE, mais peut-être pas contiguës. S'il est contigu, diff_res
contiendra soit:
<
" (si f1 ou f3 sont vides), <
", le 1er commençant toujours par " 1d
" ou "1". Pour tester ceci, nous avons:
nb=$(grep -v "^< " diff_res | wc -l) if test $nb -gt 2; then pat_found=0 elif test $nb -eq 1; then pat_found=1 else pat_found=$(sed -n -e '1{/^1d/p;/^1,/p}' diff_res | wc -l) fi
Ensuite, si pat_found vaut 1, le file sans $ PAT est le résultat diff avec seulement les lignes commençant par " <
" sans ces 2 char:
grep '^< ' diff_res | cut -c 3-
Le script complet et réorganisé ressemblerait à ceci:
# Output the desired result on stdin. f2=/tmp/f2 # Use of PID or mktmp would be better' diff_res=/tmp/diff_res # Use of PID or mktmp would be better' cat << EOF > $f2 $PAT EOF diff $FILE $f2 > $diff_res if test $? -ne 0; then grep -q '^> ' $diff_res if test $? -ne 0; then nb=$(grep -v "^< " $diff_res | wc -l) if test $nb -eq 1; then grep '^< ' $diff_res | cut -c 3- elif test $nb -eq 2; then pat_found=$(sed -n -e '1{/^1d/p;/^1,/p}' $diff_res | wc -l) test $pat_found -eq 1 && grep '^< ' $diff_res | cut -c 3- fi fi fi rm -f $f2 $diff_res
Lire le file caractère par caractère. Si le caractère correspond au premier caractère de la variable, comparez le suivant, et ainsi de suite. Si la variable entière n'est pas appariée, revenez en arrière. Vous pouvez même implémenter un algorithm plus avancé pour le faire fonctionner plus rapidement, mais comme votre langage se trouve être le shell, il serait terriblement lent de toute façon.