Como escapar de caracteres especiais em uma string?

16

Supondo $fileque o valor de um nome de arquivo seja mantido, digamos Dr' A.tif. Na programação do bash, como eu poderia escapar de aspas simples e qualquer outro caractere especial do $filesem remover o caractere especial?

Atualização em 9 de julho de 2014

A pedido do @Gilles , a seguir trecho de código que não pode manipular 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}

Depois de eu ter tentado a resposta do @Patrick on line 1, parece trabalhar para mim. Mas se eu tiver um arquivo como Dr\^s A.tif, printfcomando não parece ajudar, isso me mostra Dr\^s\ A.tif. Se eu tentar manualmente no console assim:

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

Vou ter esta saída:

Dr\\\^s\ A.tif

Alguma idéia de como lidar com isso?

huahsin68
fonte
3
em que contexto você espera usar o arquivo $? ou esse problema está atribuindo a string com o caractere especial ao arquivo $?
Rob
Na verdade, o comando find retorna uma lista de arquivos. E então eu percorro essa lista de arquivos para a variável $ file.
precisa saber é o seguinte
2
Você recebeu algumas respostas corretas aqui, mas elas provavelmente não são as respostas para a pergunta que você realmente está fazendo. Pelo seu comentário aqui, suspeito fortemente que você esteja no caminho errado. Não podemos ajudá-lo muito, porque você continua mostrando seu código. No entanto, eu recomendo que você leia Por que meu script de shell engasga com espaços em branco ou outros caracteres especiais? como pano de fundo. Mostre seu script e explique o que você quer fazer.
Gilles 'SO- stop be evil'

Respostas:

14

Você pode usar o printfbuilt-in %qpara fazer isso. Por exemplo:

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

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

A partir da documentação do bash 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
fonte
Isso não funciona com certos casos .eg quando você precisa preservar aspas duplas.
precisa saber é o seguinte
@ user3467349 funciona muito bem com aspas. Aposto que você está tentando algo parecido printf '%s' "foo". Você precisa entender como a análise de argumentos funciona primeiro no shell. Veja gnu.org/software/bash/manual/bash.html#Shell-Operation # 2 acontece antes da # 6.
Patrick
Você poderia fornecer um exemplo dessa seqüência impresso com printfe sem outras manipulaçõesIt doesn't have a: ""
user3467349
Seu problema não tem nada a ver printf. Seu problema é que você não deseja que o shell analise sua string. Para fazer isso, você precisa passar sua entrada para o shell de uma maneira que nem tente analisá-lo. Uma maneira de fazer isso seria read -r -p 'input: ' && printf '%q\n' "$REPLY"e fornecer a entrada quando solicitado.
Patrick
1
Como eu já disse várias vezes agora. Não saber como passar dados brutos para o shell não é um problema printf. Talvez você deva fazer uma pergunta em vez de criticar uma solução que não tem nada a ver com o seu problema.
Patrick
4

Experimentar:-

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

ou

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

ou se a string contiver aspas duplas: -

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

Existem bons tutoriais sobre como escapar e citar na rede. Comece com este .

garethTheRed
fonte
1

Você não precisa escapar de nenhum nome de arquivo que esteja manipulando em um script. O escape só é necessário se você deseja colocar um nome de arquivo como literal em um script ou passar vários nomes de arquivo como um único fluxo de entrada para outro script.

Como você está percorrendo a saída de find, esta é uma das maneiras mais simples (!) De lidar com todos os caminhos possíveis :

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
fonte
0

rápido e (muito) sujo

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

Muitas dessas respostas, incluindo a mais votada printf "%q", não funcionarão em todos os casos sem manipulação adicional. Eu sugeriria o seguinte (exemplo abaixo):

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

user3467349
fonte
Desculpe a pergunta n00b, mas você pode explicar como você realmente usaria isso para escapar de caracteres em uma string? Se eu copiar o código que você escreve no meu terminal, ele imprime 2015-11-07T03: 34: 41Z app [postgres.0000]: [TAG] a consulta de pesquisa de texto não contém lexemes: "" ... nada é escapado .
SharkAlley
Esse é literalmente o ponto, todos os caracteres especiais são interpretados como caracteres literais, não pelo seu significado especial. Tente ecoar "a string acima" em vez de ver a diferença.
user3467349