Поиск имен файлов, содержащих расширенные символы ASCII

Один вкладыш с использованиемsed:

sed -nf <(sed 's/$/p/' linenumberfile) contentfile

Чтобы сохранить первоначальный порядок в linenumberfile, вы можете выполнить

sed -nf <(sed 's/$/p/' linenumberfile) contentfile | paste <(nl linenumberfile | sort -n -k 2,2) - | sort -n -k 1,1 | cut -f 3-

Пояснение:

sed 's/$/p/' linenumberfile

генерирует сценарий sed, который печатает указанную строку. Затем сценарий передается в другойsed-n, чтобы подавить стандартную печать пространства шаблонов )для фактической печати. Поскольку sedобрабатывает файл содержимого построчно, вывод будет в том же порядке, что и в файле содержимого. Обратите внимание, что это однопроходный -процесс , поэтому я ожидаю, что скорость будет приемлемой.

Чтобы ускорить процесс, можно изменить pна {p;b}и добавить qв конец сгенерированного сценария sed.

Чтобы сохранить порядок строк в файле номеров строк, nlиспользуется для добавления «номеров строк» ​​в файл номеров строк. Итак, файл с номером строки

4
5
2

станет

1 4
2 5
3 2

В первом столбце записан исходный порядок в файле номеров строк.

Файл с «номера строк» ​​затем sorted и pasted на выходе sed, чтобы сделать

3 2    content_of_line2
1 4    content_of_line4
2 5    content_of_line5

затем выполняется sortредактирование с использованием 1-го столбца в качестве ключа, чтобы окончательно получить

1 4    content_of_line4
2 5    content_of_line5
3 2    content_of_line2

Наконец, cutиспользуется для удаления двух дополнительных столбцов.

Сравнительный анализ

Кажется, что sedлучше всего подходит для нескольких строк, но perl— это путь для 10000 строк, как указано в вопросе.

$ cat /proc/cpuinfo | grep -A 4 -m 1 processor
processor   : 0
vendor_id   : GenuineIntel
cpu family  : 6
model       : 60
model name  : Intel(R) Core(TM) i5-4590 CPU @ 3.30GHz

$ wc -l linenumber
10 linenumber

$ wc -l content
8982457 content

$ file content
content: ASCII text

$ time bash -c "sed -nf <(sed 's/$/p/' linenumber) content > /dev/null"    
real    0m0.791s
user    0m0.661s
sys     0m0.133s

$ time bash -c "awk 'FNR==NR { seen[$0]++ }; FNR!=NR && FNR in seen' linenumber content > /dev/null"
real    0m3.061s
user    0m2.908s
sys     0m0.152s

$ time bash -c "./ln.pl linenumber content > /dev/null"
real    0m1.706s
user    0m1.582s
sys     0m0.124s

$./genlinenumber.py 100 > linenumber
$ wc -l linenumber
100 linenumber

$ time bash -c "sed -nf <(sed 's/$/p/' linenumber) content > /dev/null"
real    0m3.326s
user    0m3.164s
sys     0m0.164s

$ time bash -c "awk 'FNR==NR { seen[$0]++ }; FNR!=NR && FNR in seen' linenumber content > /dev/null"
real    0m3.055s
user    0m2.890s
sys     0m0.164s

$ time bash -c "./ln.pl linenumber content > /dev/null"
real    0m1.769s
user    0m1.604s
sys     0m0.165s

Если требуется сохранить порядок строк, можно использовать команду после первой |, так как время незначительно.

$./genlinenumber.py 10000 > linenumber
$ wc -l linenumber
10000 linenumber

$ time bash -c "./ln.pl linenumber content > extract"
real    0m1.933s
user    0m1.791s
sys     0m0.141s

$ time bash -c "paste <(nl linenumber | sort -n -k 2,2) extract | sort -n -k 1,1 | cut -f 3- > /dev/null"
real    0m0.018s
user    0m0.012s
sys     0m0.005s
3
19.06.2020, 03:28
2 ответа
$ tree
.
|-- file 1
|   |-- file - 1 - A2.mkv
|   `-- file - 1 - A2.nfo
|-- français
|   `-- français - 2 -3.mkv
`-- tést
    `-- tést - 2 - 2.mkv

3 directories, 4 files
$ LC_ALL=C find. -name '*[![:print:]]*'
./tést
./tést/tést - 2 - 2.mkv
./français
./français/français - 2 -3.mkv

При этом в качестве локали для команды findустанавливается стандартная локаль POSIX. Класс символов printсодержит символы, которые являются частью классов символов alpha, digit, punct, а также включает символ пробела. Это означает, что проверка -name '*[![:print:]]*'будет истинной для любого имени файла, содержащего символ, который , а не в классе print.

Если вы не хотите находить имена с различными другими пробелами (, вкладки и т. д. ),используйте [![:graph:][:space:]]в качестве теста (единственная разница между printи graphзаключается в том, что graphне содержит символ пробела ).

1
18.03.2021, 23:26

Ответ Кусалананды также включает имена файлов с управляющими символами ASCII. Это может быть желательно, но в случае, если это не так, вот решение, основанное на решении Кусалананды, которое более точно отвечает на вопрос:

LC_ALL=C find. -name $'*[\x80-\xff]*'

Пример использования:

$ touch foo bár $'baz\x01'                         
$ ls
 bár  'baz'$'\001'   foo
$ LC_ALL=C find. -name $'*[\x80-\xff]*'           
./b??r
$ LC_ALL=C find. -name $'*[\x80-\xff]*' | od -tx1z
0000000 2e 2f 62 c3 a1 72 0a                             >./b..r.<
0000007

Разница с тем, что вы пробовали, заключается в том, что здесь оболочка интерпретирует шестнадцатеричные escape-последовательности вместо того, чтобы оставить это find. Кроме того, LC_ALL=Cнеобходим, вероятно, потому, что в противном случае .в регулярном выражении или *в глобах будут соответствовать этим байтам как части других символов.

1
18.03.2021, 23:26

Теги

Похожие вопросы