Неожиданный результат при использовании grep для фильтрации вывода ls

Я выполнил приведенную ниже команду awk

пример файла

prqrtwtw
ahayqlo
prasqu

ожидаемый результат

prqrtwtw
ahayqlo

команда:

k=`awk -F "" '{print NF}' examplefile | sort -nr | sed -n '1p'`

for ((i=1;i<=$k;i++))
> do
> awk -v i="$i" -F "" '$i=="q" && $(i+1) !="u"  {print $0}' examplefile;done




output

prqrtwtw
ahayqlo
0
01.05.2020, 02:45
3 ответа

В вашем конвейере есть несколько проблем.

  1. Анализ выводаlsне является хорошей идеей(см. также Почему *не *parse `ls`(и что делать вместо )?). Его формат не стандартизирован, и имена файлов могут содержать любую комбинацию байтов, кроме NUL и /. Следовательно, это не гарантирует, что имена файлов будут перечислены в однозначной форме. Часто приводимый пример включает символы новой строки (обратите внимание, как вызов lsразличными способами может привести к различным, возможно, неоднозначным результатам):

    $ touch 'foo
    > bar'
    $ ls -1
    'foo'$'\n''bar'
    $ ls | cat
    foo
    bar
    

    Являются ли fooи barдвумя разными файлами или двумя частями одного и того же имени файла?

    Безопасным способом рекурсивного поиска в каталоге файлов данного типа являетсяfind.

  2. Неэкранированная строка l*интерпретируется оболочкой как выражение подстановки . Он расширен до списка имен файлов (широким определением «файла» ), которые начинаются с lв текущем каталоге.

    # In a directory you created for testing purposes
    $ rm *; touch foo; ln -s foo link1; ln -s foo link2; ln -s foo link3
    $ set -x; ls -lR | grep l*
    + ls -lR
    + grep link1 link2 link3
    

    Параметр xtraceоболочки (, то есть set -x, доступный в нескольких оболочках и указанный в POSIX ), полезен для демонстрации эффекта расширения имени файла (подстановки):l*расширяется до link1 link2 link3и grep, следовательно, ищет строку link1в содержимомfoo(по символическим ссылкам link2иlink3).(grepне читает стандартный ввод, когда ему дается список имен файлов после шаблона для поиска ).

    Если у вас есть только один файл, имя которого начинается сl:

    # In a directory you created for testing purposes
    $ rm *; touch foo; ln -s foo link1; ln -s foo Link2; ln -s foo Link3
    $ set -x; ls -lR | grep l*
    + ls -lR
    + grep link1
    lrwxrwxrwx 1 user group 3 May  1 03:04 link1 -> foo
    

    Затем grepищет в своем стандартном вводе (выводls)строку link1, в данном случае совпадающую с одной строкой. (Чтение стандартного ввода — это то, что grepделает, когда ему не заданы имена файлов или если аргумент имени файла -равен-).

    Вы должны заключать в кавычки литеральные строки, предназначенные для передачи в качестве аргументов, чтобы оболочка не выполняла расширение имени файла. В качестве альтернативы, если это поддерживается вашей оболочкой, расширение имени файла можно отключить с помощью set -f.

  3. Если имя файла в текущем каталоге не начинается с l, выражение подстановки остается нетронутым и передается в grepв качестве первого позиционного аргумента. grepзатем интерпретирует его как регулярное выражение (по умолчанию вариант BRE ), который гласит: «для любой строки ввода сопоставьте необязательноеl(где угодно )», эффективно соответствие чему-либо:

    # In a directory you created for testing purposes
    $ rm *; touch foo
    $ ls -lR
    .:
    total 0
    -rw-r--r-- 1 user group 0 May  1 02:49 foo
    $ set -x; ls -lR | grep l*
    + ls -lR
    + grep 'l*'
    .:
    total 0
    -rw-r--r-- 1 user group 0 May  1 03:14 foo
    

    Чтобы сопоставить строку, начинающуюся с литерала l, вам нужно привязанное выражение:grep '^l'.

1
28.04.2021, 23:16

Чтобы вы знали, команда, которую вы искали, это:

ls -l | grep '^l'

Кавычки не обязательны.

Удаление параметра -Rдля lsсвязано с тем, что вы указали, что вам нужен текущий каталог, а не дерево каталогов.

И в любом случае ответы, указывающие на find, вероятно, являются лучшим решением.

0
28.04.2021, 23:16

@NasirRiley на правильном пути . Чтобы просмотреть символические ссылки в текущем каталоге, запустите find. -mindepth 1 -maxdepth 1 -type l. Тест:

$ cd "$(mktemp --directory)"
$ mkdir foo
$ touch foo/bar baz
$ ln --symbolic foo/bar ban
$ ln --symbolic bar foo/bat # symlink in subdirectory, should be ignored
$ find. -mindepth 1 -maxdepth 1 -type l
./ban
1
28.04.2021, 23:16

Теги

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