Wie kann man Sonderzeichen in einer Zeichenkette umgehen?

16

Angenommen, Sie $filehalten einen Wert für einen Dateinamen, sagen wir Dr' A.tif. Wie kann ich mich bei der Bash-Programmierung von einfachen Anführungszeichen und anderen Sonderzeichen von $filefernhalten, ohne das Sonderzeichen zu entfernen?

Aktualisierung am 9. Juli 2014

Auf Anfrage von @Gilles wird das folgende Code-Snippet nicht verarbeitet Dr' A.tif:

files=$(find /path/ -maxdepth 1 -name "*.[Pp][Dd][Ff]" -o -name "*.[Tt][Ii][Ff]")
echo "${files}" > ${TEMP_FILE}
while read file
do
   newfile=$(echo "${file}" | sed 's, ,\\ ,g') ## line 1
done < ${TEMP_FILE}

Nachdem ich aus der versucht habe Antwort von @Patrick auf line 1, so scheint es , für mich zu arbeiten. Aber wenn ich Datei wie Dr\^s A.tif, printfBefehl scheint nicht helfen, es zeigt mir Dr\^s\ A.tif. Wenn ich es manuell auf der Konsole so versuche:

printf "%q" "Dr\^s A.tif"

Ich werde diese Ausgabe haben:

Dr\\\^s\ A.tif

Hast du eine Idee, wie du damit umgehen sollst?

huahsin68
quelle
3
In welchem ​​Kontext erwarten Sie die Verwendung von $ file? Oder ist dies ein Problem beim Zuweisen der Zeichenfolge mit dem Sonderzeichen zu $ ​​file?
Rob
Tatsächlich gibt der Befehl find eine Reihe von Dateilisten zurück. Und dann durchlaufe ich diese Dateiliste in $ file variable.
Huahsin68
2
Sie haben hier einige richtige Antworten erhalten, aber dies sind wahrscheinlich nicht die Antworten auf die Frage, die Sie wirklich stellen. Aus Ihrem Kommentar hier gehe ich stark davon aus, dass Sie auf dem falschen Weg sind. Wir können Ihnen nicht viel helfen, da Sie Ihren Code nicht mehr anzeigen. Ich empfehle jedoch, dass Sie lesen Warum verschluckt sich mein Shell-Skript an Leerzeichen oder anderen Sonderzeichen? als Hintergrund. Zeigen Sie Ihr Skript und erklären Sie, was Sie tun möchten.
Gilles 'SO- hör auf böse zu sein'

Antworten:

14

Sie können das printfeingebaute mit verwenden %q, um dies zu erreichen. Beispielsweise:

$ file="Dr' A.tif"
$ printf '%q\n' "$file"
Dr\'\ A.tif

$ file=' foo$bar\baz`'
$ printf '%q\n' "$file"
\ foo\$bar\\baz\`

Aus der Bash-Dokumentation über printf:

In addition to the standard format specifications described in printf(1)
and printf(3), printf interprets:

 %b       expand backslash escape sequences in the corresponding argument
 %q       quote the argument in a way that can be reused as shell input
 %(fmt)T  output the date-time string resulting from using FMT as a format
          string for strftime(3)
Patrick
quelle
Dies funktioniert in bestimmten Fällen nicht, z. B. wenn doppelte Anführungszeichen beibehalten werden müssen.
user3467349
@ user3467349 funktioniert gut mit Anführungszeichen. Ich wette, Sie versuchen so etwas printf '%s' "foo". Sie müssen zunächst verstehen, wie das Parsen von Argumenten in der Shell funktioniert. Siehe gnu.org/software/bash/manual/bash.html#Shell-Operation # 2 geschieht vor # 6.
Patrick
Können Sie ein Beispiel dieser Zeichenfolge liefern gedruckt mit printfund ohne andere ManipulationenIt doesn't have a: ""
user3467349
Ihr Problem hat nichts damit zu tun printf. Ihr Problem ist, dass Sie nicht möchten, dass die Shell Ihre Zeichenfolge analysiert. Dazu müssen Sie Ihre Eingabe so an die Shell übergeben, dass sie nicht einmal versucht, sie zu analysieren. Ein Weg, dies zu tun, wäre read -r -p 'input: ' && printf '%q\n' "$REPLY", die Eingabe bereitzustellen, wenn Sie dazu aufgefordert werden.
Patrick
1
Wie ich schon mehrmals gesagt habe. Es ist kein Problem, nicht zu wissen, wie Rohdaten an die Shell übergeben werden sollen printf. Vielleicht sollten Sie eine Frage stellen, anstatt eine Lösung zu kritisieren, die nichts mit Ihrem Problem zu tun hat.
Patrick
4

Versuchen:-

file=Dr\'\ A.tif
echo $file
Dr' A.tif

oder

file="Dr' A.tif"
echo $file
Dr' A.tif

oder wenn die Zeichenfolge ein doppeltes Anführungszeichen enthält: -

file='Dr" A.tif'
echo $file
Dr" A.tif

Es gibt gute Tutorials zum Flüchten und Zitieren im Netz. Beginnen Sie mit diesem .

garethTheRed
quelle
1

Sie müssen keine Dateinamen maskieren, die Sie in einem Skript bearbeiten. Ein Escaping ist nur erforderlich, wenn Sie einen Dateinamen als Literal in ein Skript einfügen oder mehrere Dateinamen als einen einzigen Eingabestream an ein anderes Skript übergeben möchten .

Da Sie die Ausgabe von durchlaufen find, ist dies eine der einfachsten Möglichkeiten (!), Mit jedem möglichen Pfad umzugehen :

while IFS= read -r -d ''
do
    file_namex="$(basename -- "$REPLY"; echo x)"
    file_name="${file_namex%$'\nx'}"
    do_something -- "$file_name"
done <(find "$some_path" -exec printf '%s\0' {} +)
l0b0
quelle
0

schnell und (sehr) dreckig

find . | sed 's/^/"/' | sed 's/$/"/'
Michael
quelle
-1

Viele dieser Antworten, einschließlich der Antworten mit der höchsten Bewertung, printf "%q"funktionieren nicht in allen Fällen ohne zusätzliche Manipulation. Ich würde folgendes vorschlagen (Beispiel unten):

cat <<EOF; 2015-11-07T03:34:41Z app[postgres.0000]: [TAG] text-search query doesn't contain lexemes: "" EOF

user3467349
quelle
Entschuldigen Sie die n00b-Frage, aber können Sie erläutern, wie Sie dies tatsächlich verwenden würden, um Zeichen in einer Zeichenfolge zu maskieren? Wenn ich den Code, den Sie in mein Terminal schreiben, kopiere, wird er nur gedruckt .
SharkAlley
Das ist wörtlich der Punkt, alle Sonderzeichen werden als wörtliche Zeichen interpretiert, nicht für ihre spezielle Bedeutung. Versuchen Sie , echo „die obige Zeichenfolge“ statt den Unterschied zu sehen.
user3467349