Tengo un comando (¡no echo
!) que quiero ejecutar y que toma una ruta absoluta y una ruta relativa.
¿Cómo obtengo estos dos argumentos?
Intentar:
d=/tmp/foo;
find "$d" -type f -exec bash -c 'echo d=${1:${#d}} 1="${1%/*}"' bash {} \;
(Me gusta la búsqueda de GNU porque es recursiva, puede restringir por archivo, puede filtrar por nombre de archivo y no genera shells excesivos)
Expectativa:
mkdir -p /tmp/foo/bar/can/haz; touch /tmp/foo/bar/can/haz/bzr.txt
# cmd is run, output is:
d=bar/can/haz 1=/tmp/foo/bar/can/haz
Respuesta1
Exportar d
, luego estará disponible en su bash
secuencia de comandos en línea. Tampoco necesitas bash
nada aquí. Tu (con suerte más delgado/más rápido) sh
también serviría. Además, no es necesario ejecutar un shell por archivo. Puedes pasar más archivos a tu script en línea con la -exec cmd {} +
variante:
d=/tmp/foo
export d
find "$d" -type f -exec sh -c '
for file do
relative=${file#"$d/"}
dir=${file%/*}
relative_dir=${relative%/*}
relative_dir=${relative_dir:-.}
printf "%10s: %s\n" full "$file" \
relative "$relative" \
dir "$dir" \
reldir "$relative_dir"
done' sh {} +
Lo que da:
full: /tmp/foo/bar/can/haz/bzr.txt
relative: bar/can/haz/bzr.txt
dir: /tmp/foo/bar/can/haz
reldir: bar/can/haz
Pero si solo necesita la ruta relativa, puede ser más sencillo hacerlo:
(cd -P -- "$d" && find . -exec sh -c 'for file do...' sh {} +)
Eso también haría que los argumentos del comando pasados fueran sh
más cortos, por lo que permitiría find
pasar más argumentos a sh
.
Tenga en cuenta que no hay nada específico de GNU en su find
comando ni en el mío. Eso debería funcionar en cualquier implementación compatible con POSIX find
, no solo en la GNU. La única parte que no es POSIX en su pregunta fue obviamente bash
y el ${1:offset}
operador, que es un operador de shell Korn, no en POSIX sh
.
Para una búsqueda de archivos recursiva que le permita especificar el tipo de archivo, consulte también zsh
:
(cd -P -- "$d" &&
for file (**/*(ND.)) {
dir=$file:h
printf '%10s: %s\n' relative $file reldir $dir
})
Arriba, .
es el equivalente a find
's -type f
(solo archivos normales), mientras que D
también debe incluir archivos ocultos como find
lo hace.
Como nota al margen, en el caso general:
c=$a$b; d=${c:${#a}}
[ "$b" = "$d" ] && echo yes
No se garantiza que el resultado sea "sí", porque los operadores ${#var}
y ${var:offset}
trabajan concaracteres, nobytes.
Por ejemplo, en una configuración regional UTF-8, no generaría sí con estos valores de a
y b
:
a=$'St\xc3' b=$'\xa9phane'
Con esos, $c
contendría mi nombre ( Stéphane
) $a
contiene la mitad de ese é
carácter y $b
la otra mitad ${#a}
sería 3
(2 caracteres y 1 byte que no forman un carácter válido pero aún se cuentan).
Así $d
sería phane
, no $'\xa9phane'
.
Sin embargo, en el caso específico de d=$a/$b
, debería estar bien, ya que ninguno de los conjuntos de caracteres generalmente disponibles en las configuraciones regionales del sistema tendría un carácter distinto /
al que contiene la codificación de /
.