shell - renombrar - nombres de archivos con espacios en linux
¿Puede GNU hacer manejar nombres de archivos con espacios? (6)
El error #712 sugiere que make no maneja nombres con espacios. En ninguna parte, nunca.
Encontré una publicación de blog que decía que se implementaba parcialmente escapando de los espacios con /
( //
parece ser un error de formateo o formateo de artefacto), pero:
- No funciona en ninguna función excepto
$(wildcard)
. - No funciona al expandir listas de nombres de variables, que incluye las variables especiales
$?
,$^
y$+
, así como cualquier variable definida por el usuario. Lo que a su vez significa que mientras$(wildcard)
coincidirá con los archivos correctos, no podrá interpretar el resultado de todos modos.
Entonces, con reglas de patrones explícitas o muy simples puedes hacer que funcione, pero más allá de eso no tienes suerte. Tendrás que buscar algún otro sistema de compilación que soporte espacios. No estoy seguro de si jam / bjam does, scons , waf , ant , msbuild y msbuild deberían funcionar.
Tengo un directorio que contiene varios archivos, algunos de los cuales tienen espacios en sus nombres:
Test workspace/
Another directory/
file1.ext
file2.ext
demo 2012-03-23.odp
Utilizo el comando $(wildcard)
de GNU $(wildcard)
en este directorio, y luego repito el resultado usando $(foreach)
, imprimiendo todo. Aquí está el código:
FOO := $(wildcard *)
$(info FOO = $(FOO))
$(foreach PLACE,$(FOO),$(info PLACE = $(PLACE)))
Esto es lo que esperaría ver impreso:
Test workspace
Another directory
file1.ext
file2.ext
demo 2012-03-23.odp
Esto es lo que realmente obtendría:
Test
workspace
Another
directory
file1.ext
file2.ext
demo
2012-03-23.odp
Esto último obviamente no me sirve. La documentation para el documentation de $(wildcard)
establece que devuelve una "lista de nombres separados por espacios", pero no reconoce por completo los enormes problemas que esto plantea. Tampoco la documentation de $(foreach)
.
¿Es posible evitar esto? ¿Si es así, cómo? Cambiar el nombre de cada archivo y directorio para eliminar los espacios no es una opción.
Este método también permitirá el uso de nombres de archivo listados como $?
y variables de usuario que son listas de archivos.
La mejor forma de tratar los espacios en Make es sustituir espacios por otros caracteres.
s+ = $(subst / ,+,$1)
+s = $(subst +,/ ,$1)
$(call s+,foo bar): $(call s+,bar baz) $(call s+,bar/ baz2)
# Will also shows list of dependencies with spaces.
@echo Making $(call +s,$@) from $(call +s,$?)
$(call s+,bar/ baz):
@echo Making $(call +s,$@)
$(call s+,bar/ baz2):
@echo Making $(call +s,$@)
Salidas
Making bar baz
Making bar baz2
Making foo bar from bar baz bar baz2
A continuación, puede manipular de forma segura las listas de nombres de archivos utilizando todas las funciones de GNU Make. Solo asegúrese de eliminar los + ''s antes de usar estos nombres en una regla.
SRCS := a/ b.c c/ d.c e/ f.c
SRCS := $(call s+,$(SRCS))
# Can manipulate list with substituted spaces
OBJS := $(SRCS:.c=.o)
# Rule that has object files as dependencies.
exampleRule:$(call +s,$(OBJS))
# You can now use the list of OBJS (spaces are converted back).
@echo Object files: $(call +s,$(OBJS))
a/ b.o:
# a b.o rule commands go here...
@echo in rule: a b.o
c/ d.o:
e/ f.o:
Salidas
in rule: a b.o
Object files: a b.o c d.o e f.o
Esta información proviene del blog que publicaron todos los demás.
La mayoría de la gente parece recomendar no usar espacios en las rutas o usar las rutas de Windows 8.3, pero si debe usar espacios, los espacios de escape y las sustituciones funcionan.
GNU Make lo hace muy mal con nombres de archivo separados por espacios.
Los espacios se usan como delimitadores en la lista de palabras en todo el lugar.
Esta publicación de blog resume bien la situación, pero ADVERTENCIA: usa incorrectamente // en lugar de /
target: some/ file some/ other/ file
some/ file some/ other/ file:
echo done
También puedes usar variables, así que esto también funcionaría
VAR := some/ file some/ other/ file
target: $(VAR)
$(VAR):
echo done
Solo la función de wildcard
reconoce el escape, por lo que no puedes hacer nada elegante sin mucho dolor.
Pero no olvide que su caparazón usa espacios como delimitadores también .
Si quisiera cambiar el echo done
para touch $@
, tendría que agregar una barra para escapar de mi caparazón.
VAR := some/ file
target: $(VAR)
$(VAR):
touch $(subst /,//,$@)
o, más probablemente, use comillas
VAR := some/ file some/ other/ file
target: $(VAR)
$(VAR):
touch ''$@''
Al final, si quiere evitar mucho dolor, tanto en la creación de GNU como en su caparazón, no coloque espacios en sus nombres de archivo. Si lo hace, es de esperar que las capacidades limitadas de Make sean suficientes.
La pregunta original decía que "renombrar no es una opción", sin embargo, muchos comentaristas han señalado que el cambio de nombre es prácticamente la única forma en que Make puede manejar espacios. Sugiero una manera intermedia: use Make para cambiar el nombre de los archivos temporalmente y luego cámbieles el nombre. Esto le da todo el poder de Make con reglas implícitas y otras bondades, pero no estropea su esquema de nombres de archivo.
# Make cannot handle spaces in filenames, so temporarily rename them
nospaces:
rename -v ''s/ /%20/g'' */ *
# After Make is done, rename files back to having spaces
yesspaces:
rename -v ''s/%20/ /g'' *%20*
Puede llamar a estos objetivos a mano con make nospaces
y make yesspaces
, o puede tener otros objetivos que dependen de ellos. Por ejemplo, es posible que desee tener un destino "push" que se asegure de volver a poner los espacios en los nombres de los archivos antes de volver a sincronizarlos con un servidor:
# Put spaces back in filenames before uploading
push: yesspaces
git push
[Nota: Probé la respuesta que sugería usar +s
s+
pero hizo que mi Makefile fuera más difícil de leer y depurar. Renuncié a eso cuando me dio un bufido sobre las reglas implícitas me gusta: %.wav : %.ogg ; oggdec "$<"
%.wav : %.ogg ; oggdec "$<"
.]
Otras respuestas ya cubren bastante bien el problema. Acabo de hacer un ejemplo para mostrar que el /
-escaping también funciona para las dependencias.
$ make --version
GNU Make 4.0
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ sed ''s/^ //t/'' >Makefile <<''_EOF_''
X = $(shell find -name ''x*'' -type f | sed ''s/ /// /g'')
all: $(X)
head $(X)
_EOF_
$ touch ''x 1''
$ touch ''x 2''
$ make
head ./x/ 2 ./x/ 1
==> ./x 2 <==
==> ./x 1 <==
$
Si está dispuesto a confiar un poco más en su shell, esto le da una lista que puede contener nombres con espacios bien:
$(shell find | sed ''s: :// :g'')