Да, командная строка
будет различаться в зависимости от того, какой именно системный вызов exec *
был выполнен, и полностью квалифицированный путь может отличаться от того, который env (1)
обнаруживает при поиске пути.
bash-4.1$ cat aaa
#!/bin/bash
xxd /proc/$$/cmdline
bash-4.1$ cat bbb
#!/usr/bin/env bash
xxd /proc/$$/cmdline
bash-4.1$ ./aaa
0000000: 2f62 696e 2f62 6173 6800 2e2f 6161 6100 /bin/bash../aaa.
bash-4.1$ ./bbb
0000000: 6261 7368 002e 2f62 6262 00 bash../bbb.
bash-4.1$
strace
показывает подробности:
bash-4.1$ strace ./aaa 2>&1 | grep exec
execve("./aaa", ["./aaa"], [/* 57 vars */]) = 0
bash-4.1$ strace ./bbb 2>&1 | grep exec
execve("./bbb", ["./bbb"], [/* 57 vars */]) = 0
execve("/sbin/bash", ["bash", "./bbb"], [/* 57 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/sbin/bash", ["bash", "./bbb"], [/* 57 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/local/sbin/bash", ["bash", "./bbb"], [/* 57 vars */]) = -1 ENOENT (No such file or directory)
execve("/bin/bash", ["bash", "./bbb"], [/* 57 vars */]) = 0
bash-4.1$
Если это сценарий только для Linux, то местоположение bash
, скорее всего, не будет изменяться (исключение: есть хранилище программного обеспечения, которое включает bash
, в другом месте). Следовательно, использование полного пути, вероятно, имеет наибольший смысл, поскольку это позволяет избежать ошибок env (1)
при поиске пути и обеспечивает совместимость с инструментами инициализации.
Первые два примера являются выходом из положения.
*<>:\|?*
Вы не можете начать с *
. *
означает 0 или более предыдущих атомов. Он также говорит <
, за которым следует >
, за которым следует :
…, а ?
— это специальный символ. *[<>:\|?]*
Это ближе к тому, что вы используете класс символов, но все же *
в начале. [<>:\|?]
Это совпало бы, если бы это было совпадение под-регулярного выражения, но это не так. Вам нужно сопоставить полное имя файла, включая путь к каталогу. Поэтому добавьте коды регулярных выражений, чтобы потреблять данные до и после.(.
— любой символ, *
— ноль или более гарантий предыдущего атома. Поэтому .*
будет соответствовать чему угодно.)
Поэтому попробуйте.*[<>:\|?].*
Вы не собираетесь заменять ничего подобного, и вы не сказали нам, на что вы хотите их заменить.
Используйте -name
вместо -regex
(, так как это имена файлов, которые вас действительно интересуют, и -regex
соответствует всему пути):
find folder -type d -name '*[<>:\|?]*'
Будет найден любой каталог внутри или ниже folder
, имя которого содержит хотя бы один из символов <
, >
, :
, \
, |
или ?
.
Чтобы удалить эти символы из имен каталогов:
find folder -depth -type d -name '*[<>:\|?]*' \
-execdir bash -c 'mv "$1" "${1//[<>:\|?]/}"' bash {} ';'
Это предполагает, что новое имя переименованного каталога еще не является именем существующего каталога. Добавление теста на конфликты имен:
find folder -depth -type d -name '*[<>:\|?]*' \
-execdir bash -c '[ ! -e "${1//[<>:\|?]/}" ] && mv "$1" "${1//[<>:\|?]/}"' bash {} ';'
Это позволит избежать попыток переименовать каталог, если новое имя уже существует
Команда mv
выполняется в дочерней оболочке bash
. Оболочка выполняется с родительским каталогом найденного каталога в качестве рабочего каталога. Он использует подстановку специального параметраbash
-для удаления всех оскорбительных символов из имен файлов найденных каталогов.
Команда также использует -depth
для глубокого -первого обхода структуры каталогов в folder
. Без этого find
попытается войти в каталоги, которые вы только что переименовали, и потерпит неудачу.
Связанные: