Errore di script Bash con stringhe con percorsi con spazi e caratteri jolly


25

Sto riscontrando problemi nel mettere a nudo le basi dello scripting di Bash. Ecco cosa ho finora:

#!/bin/bash
FILES="/home/john/my directory/*.txt"

for f in "${FILES}"
do
  echo "${f}"
done

Tutto quello che voglio fare è elencare tutti i .txtfile in un forciclo in modo da poter fare cose con loro. Ma lo spazio in my directorye l'asterisco *.txtnon stanno giocando bene. Ho provato a usarlo con e senza virgolette doppie, con e senza parentesi graffe sui nomi delle variabili e ancora non riesco a stampare tutti i .txtfile.

Questa è una cosa molto semplice, ma sto ancora lottando perché sono stanco e non riesco a pensare dritto.

Che cosa sto facendo di sbagliato?

Sono stato in grado di applicare correttamente lo script sopra se i miei FILES non hanno uno spazio o un asterisco ... Ho dovuto sperimentare con o senza l'uso di virgolette doppie e parentesi graffe per farlo funzionare. Ma nel momento in cui ho entrambi gli spazi e un asterisco, rovina tutto.

Risposte:


33

Tra virgolette, *non si espanderà in un elenco di file. Per utilizzare correttamente un tale carattere jolly, deve essere al di fuori delle virgolette.

Anche se il carattere jolly si espandesse, l'espressione "${FILES}"comporterebbe una singola stringa, non un elenco di file.

Un approccio che funzionerebbe sarebbe:

#!/bin/bash
DIR="/home/john/my directory/"
for f in "$DIR"/*.txt
do
  echo "${f}"
done

In quanto sopra, i nomi dei file con spazi o altri caratteri difficili verranno gestiti correttamente.

Un approccio più avanzato potrebbe utilizzare gli array bash:

#!/bin/bash
FILES=("/home/john/my directory/"*.txt)
for f in "${FILES[@]}"
do
  echo "${f}"
done

In questo caso, FILESè una matrice di nomi di file. Le parentesi che circondano la definizione ne fanno un array. Si noti che *è al di fuori delle virgolette. Il costrutto "${FILES[@]}"è un caso speciale: si espanderà in un elenco di stringhe in cui ogni stringa è uno dei nomi dei file. I nomi dei file con spazi o altri caratteri difficili verranno gestiti correttamente.


1
grande che ha funzionato
John,

Vale la pena notare che se si passano percorsi come questo in giro attraverso funzioni, è necessario assicurarsi di citare la variabile da sola anziché concatenarla come parte di una stringa più grande: for f in "$DIR"/*.txt= fine for f in "$DIR/*.txt"= rotture
pospi

7

Mentre l'uso di array come mostrato da John1024 ha molto più senso, qui, puoi anche usare l'operatore split + glob (lasciando una variabile scalare non quotata).

Poiché desideri solo la parte globale di quell'operatore, devi disabilitare la parte divisa :

#! /bin/sh -
# that also works in any sh, so you don't even need to have or use bash

file_pattern="/home/john/my directory/*.txt"
# all uppercase variables should be reserved for environment variables

IFS='' # disable splitting

for f in $file_pattern # here we're not quoting the variable so
                       # we're invoking the split+glob operator.
do
  printf '%s\n' "$f" # avoid the non-reliable, non-portable "echo"
done

0

Quello che puoi fare è lasciare solo i caratteri jolly al di fuori delle virgolette.
Qualcosa di simile:
una in "file con spazi" * "txt"
non
elaborazione
fatta
Se i caratteri jolly stessi si espandono per gli spazi, allora avrete bisogno di t utilizzare un file per ogni approccio linea, come l'uso di ls -l per generare l'elenco dei file e utilizzare bash read per ottenere ogni file.


-1

Quando si desidera elaborare un set di file, si considera, al loro nome potrebbe essere spazio o altro codice scape sarà lì, quindi prima di iniziare il processo come for loopo find commandimpostare il IFS bash env variable:

IFS=$(echo -en "\n\b")
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.