Citare un nome file in uno script passato a chmod?


1

Ho problemi a citare un nome file che alla fine è passato a chmod. Lo script è stato originariamente scritto per SSH StrictModese authorized_keys, ma ho dovuto espanderlo a causa di un problema UMASKche ha causato disagio al filesystem. Lo script è di seguito, e sta producendo carichi di:

chmod: /Users/<user>/Library/Application: No such file or directory
chmod: Support/TextMate/Managed/Bundles/HTML.tmbundle/Macros/Delete: No such file or directory
chmod: whitespace: No such file or directory
chmod: between: No such file or directory
chmod: tags.plist: No such file or directory
...
chmod: /Users/<user>/Library/Caches/com.operasoftware.Opera/Media: No such file or directory
chmod: Cache/index: No such file or directory
cut: stdin: Illegal byte sequence
...

Ho provato alcune soluzioni alternative, ma nessuna di queste ha aiutato. Ho provato a fare una doppia citazione come ""$file"", ma il problema è persistito. Ho anche provato i segni di spunta posteriori (che sono scoraggiati in questo caso), ma il problema persisteva.

Il più vicino che ho avuto modo di citare era il disfunzionale "\"""$file""\"". Ma poi si è chmodlamentato del fatto che il nome file (tra virgolette) non fosse un vero file:

$ sudo ~/fix-perms.sh
chmod: "/Users/Shared/.localized": No such file or directory
chmod: "/Users/<user>/.CFUserTextEncoding": No such file or directory
chmod: "/Users/<user>/.lesshst": No such file or directory

Come posso citare il nome del file che ne risulta findche viene passato chmod? O come posso chmodprendere il nome del file come singolo argomento?


$ cat ~/fix-perms.sh 
#!/bin/bash

# Directories
find /Users/* -type d -exec chmod 0700 {} \;
find /Users/Shared -type d -exec chmod 0777 {} \;

# Files
for file in `find /Users/* -type f`;
do
    if [ `file "$file" | cut -d":" -f 2 | grep -i -c executable` -eq 0 ];
    then
        `chmod 0600 "$file"`
    else
        `chmod 0700 "$file"`
    fi
done

for user in `ls -A /Users`;
do
    if [ -e "/Users/$user/.ssh/authorized_keys" ];
    then
        chmod 0600 "/Users/${user}/.ssh/authorized_keys"
    fi
done

1
Sei investito in script bash o ci sono altre opzioni che accetteresti? Se sei bash, potrei essere in grado di rielaborare le cose per essere find | xargs sudo chmodinvece di srotolare tutto in un ciclo for in cui gli spazi ti fanno soffrire per iterare sulla variabile.
bmike

Risposte:


3

fwiw, find [options] -print0se usato insieme a (reindirizzato a) xargs -0 [options], gestisce i nomi dei file con spazi, senza fare casini con i forloop o IFS:

find /Users ! -path '/Users/Shared*' -type f -print0 | xargs -0 -I {} \
    bash -c 'if [[ "$(file -b --mime-type -- "{}")" = "application/x-mach-binary" ]]; then
                 chmod 700 "{}"
             else
                 chmod 600 "{}"
             fi'

1
grazie @patrix, è meglio di quello che mi sarei inventato.
mtklr,

Sì, ci sono molti modi per fare le cose con la shell ... (Lo trovo frustrante a volte).

Lieve alternativa: find /path -type d -maxdepth 1 ! -perm 0700 -exec chmod 0755 {} \; L' -maxdepth #è arbitraria, a volte non è necessario o vuole andare troppo in basso albero.

1

Sono stato in grado di risolvere il problema modificando IFSper IFS=$(echo -en "\n\b")e non citando il nome del file. IFSè un separatore di campo interno , viene utilizzato (tra gli altri) per la suddivisione delle parole dopo le espansioni della shell e include uno spazio per impostazione predefinita.

Ho trovato il IFStrucco su BASH Shell di nixCraft : For Loop File Names With Spaces .

$ cat fix-perms.sh
#!/bin/bash

SAVED_IFS=$IFS
IFS=$(echo -en "\n\b")

# Directories
chmod 0755 /Users
find /Users/* -type d -exec chmod 0700 {} \;
find /Users/Shared -type d -exec chmod 0777 {} \;

# Files
for file in `find /Users/* -type f`;
do
    if [ `file "$file" | cut -d":" -f 2 | grep -i -c executable` -eq 0 ];
    then
        chmod 0600 "$file"
    else
        chmod 0700 "$file"
    fi
done

for user in `ls -A /Users`;
do
    if [ -e "/Users/$user/.ssh/authorized_keys" ];
    then
        chmod 0600 "/Users/${user}/.ssh/authorized_keys"
    fi
done

IFS=$SAVED_IFS

Non posso davvero raccomandare questo metodo, dal momento che fallirà per i nomi di file con avanzamenti di riga (o campane? Perché è lì ...). Supponiamo che un utente abbia creato un file chiamato a\n*\nb- verrà analizzato in tre parole: "/ Users / qualcosa / a", * e "b"; quindi * verrà espanso in un elenco di file e sottodirectory nella directory in cui ci si trova e lo script modificherà le autorizzazioni (forse errato, poiché le sottodirectory non sono eseguibili). Ma i tuoi utenti probabilmente non lo faranno. Probabilmente ...
Gordon Davisson il

@Gordon - Non ho cercato i meta-personaggi della shell, ma intendevo farlo. Grazie per avermi parlato della campana ... Perché nel mondo \bc'è, ma no \t? Ingenuamente, ho pensato che \bfosse la scheda o il backspace. In un certo senso ho capito il backspace, ma la campana non ha senso per me.

@Gordon - apparentemente, la pagina di Bash utilizza un presupposto errato per OS X. Su OS X in HFS +, i nomi dei file possono contenere \0; vedi Mac OS X Lion: cosa sono i caratteri non validi per un nome file? su Super User. Un leader \0è probabilmente un buon modo per nascondere un virus ...

0

findpuò gestire spazi nei nomi dei file. Stai for loopscausando i problemi. Puoi mettere la tua logica in più findcomandi. Non tutte le directory nella cartella home di un utente dovrebbero essere accessibili solo a se stesse. Vengono in mente pubblico e siti. Puoi risolverli separatamente in un altro comando find.

find /Users/* ! -path '/Users/Shared*'  -type d ! \( -name Public -o -name Sites \) -exec chmod 0700 {} +

Il comando esclude la directory condivisa insieme alle directory Public e Sites, quindi modifica le autorizzazioni per le restanti directory.

Puoi usare +nelle tue finddichiarazioni per findagire come se fosse xargs.

find /Users/Shared -type d -exec chmod 0777 {} +

Supponendo che i file eseguibili nella cartella principale di un utente siano bundle di applicazioni, è possibile farlo.

find /Users/* ! -path '/Users/Shared*' type f ! perm -755 -exec chmod 0600 {} +

Grazie fd0. "find può gestire gli spazi nei nomi dei file. I tuoi cicli for stanno causando i problemi." - Ok, bene, mi prenderò in parola. E adesso? Non mi dici davvero come ripararlo. (Non preoccuparti per Sharedo $HOME/Public. Questa è la ciliegina sulla torta. La preoccupazione principale sono le autorizzazioni per le home directory).

0

La soluzione di mtklr (e Patrix ') funzionerà, ma trovo che sia più semplice usare un while readciclo quando si ha a che fare con un elenco di file da find ... -print0:

find /Users '!' -path '/Users/Shared*' -type f -print0 |
    while IFS= read -d '' -r file; do
        if file "$file" | grep -iq ": .*executable"; then
            chmod 700 "$file"
        else
            chmod 600 "$file"
        fi
    done

read -d ''usa i null come delimitatore. Ho anche usato -rper impedire che tentasse di analizzare le fughe, e IFS=per evitare di tagliare gli spazi bianchi alla fine del nome del file (e poiché è un prefisso del readcomando, si applica solo a quello e non è necessario ripristinarlo in seguito).

A proposito, ho anche usato if ... | grep -q ...- -qdice di grepnon produrre nulla, ma il suo stato di uscita avrà successo solo se ha trovato almeno una corrispondenza. E dal momento ifche verifica solo lo stato di uscita del comando in esso, questo è tutto ciò che è necessario.

A proposito, questo si basa principalmente su BashFAQ # 20: Come posso trovare e gestire in modo sicuro i nomi dei file contenenti nuove righe, spazi o entrambi? . Consiglio di dargli un'occhiata ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.