Нетипичный «ls» или как развлекаются линуксоиды +59



Однажды в телеграм чат питерского сообщества линуксоидов SPbLUG я кинул забавную задачку:

Выведите список файлов в домашней директории максимально возможным количеством способов, без использования ls или его алиасов(1 способ — 1 балл)

Такое же задание чуть позже прилетело в ещё один чат, и вот что из этого получилось:

1. echo и print


for i in ~/*  ~/.* ; do echo $i ; done

Ровно то же самое выдаст замена команды echo на print.
На самом деле можно обойтись и без цикла, получится не так красиво, но под условие задачи вполне подходит.

echo ~/* ~/.*

2. tree


Более очевидный способ — использовать tree, который практически ls если подобрать правильные ключи.

tree -aiL 1 ~

3. find


Тоже более чем очевидное решение.

find ~ -maxdepth 1 -mindepth 1

4. du


Да, про du народ не забыл.

du -ad 1 ~

5. tar


Переходим к водным процедурам тонким извращениям.

tar -cvf /dev/null --no-recursion ~/* ~/.* 2>null

6. 7. Perl и Python


Так как в условии задачи я забыл поставить ограничение на интерпретаторы, которые в современных линуксах обычно есть в системе из коробки, то кашевары и змееводы не смогли остаться в стороне:
Perl:

perl -e 'use feature "say"; opendir my $dh, "." or die "Could not open . for reading: $!\n"; while (my $thing = readdir $dh) { say $thing; };'

Python:

echo -e "import os\nfor i in os.listdir(os.getenv('HOME')): print(i)" | python

Вне конкурса


Выдали на гора даже исходник на C, но хоть компилятор и присутствует практически везде, кроме всяких emmbedded дистрибутивов, я посчитал это уж совсем полным беспределом. ;-)

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

#define HOME getenv("HOME")

int main(int argc, char const *argv[])
{
    struct dirent *dp;
    DIR *dir = opendir(HOME);
        while ((dp = readdir(dir)) != NULL)
            printf("%s\n", dp->d_name);
    closedir(dir);

    return 0;
}

P.S.


Вероятно, где-то в coreutils/findutils участники развлекухи что-то пропустили. Были неудачные попытки использовать less/more, но может у хабровчан тоже появились идеи по нестандартному использованию стандартных утилит.

Upd. 1


Спасибо хабр! Комменты, это просто праздник какой-то! И по их мотивам я готовлю новый пост. Оставайтесь на связи!

Upd. 2


Как я и обещал, вторая часть «Марлезонского балета».

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (128):

  1. m03r
    /#20608599

    cd ~; vi .
    (zsh) ~/ [tab][tab]

    • SlavniyTeo
      /#20610113

      [tab][tab] — слишком интерактивно


      echo -e 'echo \t\ty\b\b\b\b\b\b\b' | bash -i

      К сожалению, выведет пару лишних строк.

  2. eumorozov
    /#20608649

    Конечно пропустили. В coreutils, например, есть команда dir. :)

  3. cru5ader
    /#20608667

    dir ~

  4. cru5ader
    /#20608673

    vim .

  5. 027
    /#20608889 / +1

    cp ~/ <Tab><Tab>
    mv ~/ <Tab><Tab>
    dd if=~/ <Tab><Tab>
    и т.п.

    • MaxVetrov
      /#20616971

      можно несуществующую команду:
      a ~/[TAB][TAB]
      ! ~/[TAB][TAB]
      можно для текущей директории такое:
      ![TAB][TAB][TAB]

      PS. Пока эксперементировал, нашел devbash :)
      `/[TAB][TAB]

      выдает:

      binbash: bad substitution: no closing "`" in `/bin
      etcbash: bad substitution: no closing "`" in `/etc
      lib64bash: bad substitution: no closing "`" in `/lib64
      mntbash: bad substitution: no closing "`" in `/mnt
      runbash: bad substitution: no closing "`" in `/run
      tmpbash: bad substitution: no closing "`" in `/tmp

      bootbash: bad substitution: no closing "`" in `/boot
      homebash: bad substitution: no closing "`" in `/home
      libx32bash: bad substitution: no closing "`" in `/libx32
      optbash: bad substitution: no closing "`" in `/opt
      sbinbash: bad substitution: no closing "`" in `/sbin
      usrbash: bad substitution: no closing "`" in `/usr

      cdrombash: bad substitution: no closing "`" in `/cdrom
      libbash: bad substitution: no closing "`" in `/lib
      lost+foundbash: bad substitution: no closing "`" in `/lost+found
      procbash: bad substitution: no closing "`" in `/proc
      srvbash: bad substitution: no closing "`" in `/srv
      varbash: bad substitution: no closing "`" in `/var

      devbash: bad substitution: no closing "`" in `/dev
      lib32bash: bad substitution: no closing "`" in `/lib32
      mediabash: bad substitution: no closing "`" in `/media
      rootbash: bad substitution: no closing "`" in `/root
      sysbash: bad substitution: no closing "`" in `/sys

      • 027
        /#20616993

        Я за эти клавиатурные таб-таб каюсь, ибо совсем забыл, что:

        • автоподстановка не является всеобщим правилом для *никсов, а есть только там, где она сознательно реализована мейнтейнером для конкретного окружения конкретной версии*;
        • есть способ посмотреть без выстукивания по клаве, что выдаст автоподстановка в разных ситуациях, а именно — команда баша compgen.

        *) например, автодополнение в моей системе живет тут: /etc/bash_completion и тут: /etc/bash_completion.d.

        • MaxVetrov
          /#20621781

          Заинтересовался автодополнением.)
          А с помощью complete можно эту задачу решить?

  6. POPSuL
    /#20608947

    Так конечно делать не нужно, но если уж совсем нет других вариантов…

    Я предупреждал
    yes "n" | rm -i $HOME/* $HOME/.* 2>&1 | grep -o "$HOME[^»'’]*"
    

    • shanlove
      /#20611347

      Можно и чуть покороче))
      rm -fv ~/* 2> /dev/null

      • Oxyd
        /#20612957

        Ну и шуточки у вас. ;-)

    • 027
      /#20612117

      Я предупреждал

      Но мы же все делаем бэкап $HOME, правда?

      • orthanner
        /#20617763

        Конечно. В $HOME/.backup :-)

        • 027
          /#20621593 / +1

          А-а-а! Ты знал!!!

          $ ls -1 ~
          ...
          027
          1
          backup
          projects
          scripts
          Видео
          Документы
          ...
          

          • SlavniyTeo
            /#20624479

            Я не осуждаю, но в этом топике листинг домашней директории можно было привести и без использования ls

  7. Pilat
    /#20608949

    Самый простой способ — создать архив файлов в нужной директории а потом вывести листинг архива. Это поддерживает куча архиваторов. Можно и рекурсивно.

    • vladkorotnev
      /#20609127

      Что-то подобное через tar как раз и описано, только листинг выводится при упаковке

  8. deniss-s
    /#20608981

    grep "" -lr .
    less .
    

    • 027
      /#20609045

      Вышенаписанные варианты

      $ less .
      $ vi .
      у меня выводят:
      . is a directory

      grep "" -lr .
      выводит все потроха рекурсивно (не уверен, что это соответствует условию задачи)

      • deniss-s
        /#20609099

        Странно, что less себя так ведёт, может зависит от шела? У меня в bash показывает содержание текущей директории.


        С grep можно попробовать такой вариант grep "" -l ./*, правда формат вывода директорий, не очень красив.

        • 027
          /#20609131

          Странно, что less себя так ведёт, может зависит от шела?

          Наверное. У меня
          $ bash --version
          GNU bash, версия 4.4.20(1)-release (x86_64-pc-linux-gnu)
          $ lsb_release -d
          Description:	Linux Mint 19.1 Tessa


          «nano .» то же самое пишет, разве что по-русски.

          • deniss-s
            /#20609225

            У меня в Fedora работает, а у коллеги на Mint нет. :)

            • 027
              /#20609233

              Стало быть, способ не универсален, только и всего.

          • eumorozov
            /#20609793

            Проверять надо при помощи type less (у меня fish, не помню, как в bash записывается, кажется так же) и less -V.

          • DerRotBaron
            /#20610623

            И от шелла и не от шелла. В Fedora переменная LESSOPEN определяется на скрипт, выводящий в случае директории вывод ls.


            Детали
            [user@localhost ~]$ rpm -ql less
            /etc/profile.d/less.csh
            /etc/profile.d/less.sh
            /usr/bin/less
            ...
            /usr/bin/lesspipe.sh
            ...
            [user@localhost ~]$ cat /etc/profile.d/less.sh 
            # less initialization script (sh)
            # All less.*sh files should have the same semantics!
            if [ -z "$LESSOPEN" ] && [ -x /usr/bin/lesspipe.sh ]; then
                # The '||' here is intentional, see rhbz#1254837.
                export LESSOPEN="||/usr/bin/lesspipe.sh %s"
            fi
            [user@localhost ~]$ cat /usr/bin/lesspipe.sh                
            #!/bin/sh
            ...
            # The script should return zero if the output was valid and non-zero
            # otherwise, so less could detect even a valid empty output
            # (for example while uncompressing gzipped empty file).
            # For backward-compatibility, this is not required by default. To turn
            # this functionality there should be another vertical bar (|) straight
            # after the first one in the LESSOPEN environment variable:
            # export LESSOPEN="||/usr/bin/lesspipe.sh %s"
            ...
            if [ -d "$1" ] ; then
                    ls -alF -- "$1"
                    exit $?
            fi
            ...

  9. 027
    /#20608999

    rsync --list-only ~/

  10. kashtan404
    /#20609067

    Я считаю, grep и stat незаслуженно забыли:

    grep -l '.*' ./*
    stat ./*
    

    • 027
      /#20609267

      stat незаслуженно забыли

      stat дает чрезмерно говорливый выхлоп, а в задаче надо просто список файлов.
      Тогда уж лучше file:
      file ~/*

      Но этот способ не показывает скрытые файлы (как и все иные, основанные на разворачивании звездочки интерпретатором). Может, как-то можно через переменные окружения на это повлиять?

      • polar_yogi
        /#20611435

        Говорливость stat регулируется, можно выводить от только имени до хотя json какого нибудь.
        Например:
        stat -c "%A %G:%U %s %x %n" * \.*

      • Oxyd
        /#20612991

        Ну говорливый. Говорилка-то угоманивается… ;-)

        stat ~/* ~/.*|grep "/home"|awk '{print $2}

        • 027
          /#20613019

          Ага, точно. Будто слишком говорливой теще заткнули рот кляпом, а когда это не помогло, стали душить удавкой. :)
          Удawkой, кхм…

          • Oxyd
            /#20613025

            Мы их душили, душили! Душили, Душили!
            © Шариков.

    • KorDen32
      /#20609979

      grep так не покажет пустые файлы

      grep -l '.*' ./* || grep -L '.*' ./*

  11. deniss-s
    /#20609115

    gzip -cv1 ./* | gzip -l

    • Oxyd
      /#20612993

      Что-то он у меня в хомяке чуть ли не треть файлов не показал…

  12. Artyushov
    /#20609197

    head -n 0 -v ./*

  13. Stronix
    /#20609731

    echo -e «import os\nfor i in os.listdir(os.getenv('HOME')): print(i)» | python

    Так аккуратнее, на мой взгляд:
    python -c "import os;  print(os.listdir('.'))"

  14. RumataEstora
    /#20610109

    1. echo и print

    Эти команды не идентичны. Возможно Вы имели в виду printf, но она может сбоить в некоторых случаях, хотя echo — тоже.


    1. tar

    У вас мешанина в примере — /dev/null и null.


    1. Perl

    Нет нужды использовать последние фичи языка, но можно использовать внутренние возможности:


    perl -le '$d = "."; opendir D, $d or die "Could not open $d for reading: $!\n"; print while (readdir D)'

    И, кстати, вот еще один перловый ls:


    perl -le 'print while <.* *>'

    • azmar
      /#20610733

      На случай если есть руби из коробки:
      ruby -e 'puts Dir.entries "."'

      • 027
        /#20612185

        На случай, если есть php в коробке.

        Для текущей:

        php -r 'print_r(scandir("."));'

        Для домашней:
        php -r 'print_r(scandir($argv[1]));' -- ~

        Для всякой:
        php -r 'print_r(scandir($argv[1]));' -- <some_dir>

        • azmar
          /#20612531

          Интересно есть ли дистрибутив, в котором пхп прямо в базовой поставке)

          • 027
            /#20612545

            Любой, снабженный веб-мордой на php. Openmediavault, например.

  15. rionnagel
    /#20610301

    [любые символы][space][tab][tab]
    GNU bash, version 5.0.7(1)-release
    urxvt v9.22

    • 027
      /#20610369

      любые

      У меня, как минимум, не работает с кавычками и апострофом.

      • rionnagel
        /#20610377

        Я утрировал. Не совсем любые.

      • 027
        /#20610405

        О, символы вообще не нужны! Достаточно просто пробела.

        • rionnagel
          /#20610439

          У меня не воспроизводится (

          • 027
            /#20610575

            Зависит от окружения, стало быть. Сейчас потыкал на контейнере с убунтой 14.04 — совсем не так реагирует на колочение таба. Плохой способ.

  16. Zoro
    /#20610511 / +1

    getfacl ~/* ~/.*

    • Zoro
      /#20611029

      getfacl ~/* ~/.* | grep "# file" | awk '{print $3}'

  17. Zoro
    /#20610799 / +1

    ls -i /home
    529589 test

    debugfs /dev/sda1
    debugfs: stat <529589>
    Inode: 529589 Type: directory Mode: 0755 Flags: 0x80000
    Generation: 2678704405 Version: 0x00000000:00000007
    User: 1000 Group: 1000 Project: 0 Size: 4096
    File ACL: 0
    Links: 4 Blockcount: 8
    Fragment: Address: 0 Number: 0 Size: 0
    ctime: 0x5d721b09:c9c4305c — Fri Sep 6 08:38:33 2019
    atime: 0x5d78e0f5:a027932c — Wed Sep 11 11:56:37 2019
    mtime: 0x5d721b09:c9c4305c — Fri Sep 6 08:38:33 2019
    crtime: 0x5d721abd:243d5800 — Fri Sep 6 08:37:17 2019
    Size of extra inode fields: 32
    Inode checksum: 0xa0aa0f22
    EXTENTS:
    (0):2106181

    берем
    (0):2106181

    dd if=/dev/sda1 of=image.dd bs=4096 count=1 skip=2106181

    hexdump -C image.dd | awk '{print $18}'
    |................|
    |................|
    |.profile........|
    |.bashrc.........|
    |.bash_logout....|
    |.....cache......|
    |.....gnupg......|
    |.....sudo_as_adm|
    |in_successful...|
    |................|

    |............&..W|

    :)

    • Oxyd
      /#20612999

      Круто! Реально круто! Осталось понять как избавиться от ls -i…

      • POPSuL
        /#20613057

        Можно через stat узнать inode

  18. iig
    /#20611003 / +1

    stat *|awk '/File:/{print $2}'

    • Oxyd
      /#20613009

      Хорошо, до той поры пока не наткнётся на русскую локаль… ;-) Ну или например китайскую.

      • POPSuL
        /#20613059

        LANG=C stat ... никто не отменял :)

        • 027
          /#20613105

          О, кстати!
          Кто объяснит, почему в подобных конструкциях после задания переменной не нужно ставить точку с запятой? Это же отдельная команда, по идее.

          • POPSuL
            /#20614015

            Нет, это изменение environment variable для запускаемой программы, а не глобально. именно поэтому при "пайпинге" нужно указывать для каждой команды свои переменные окружения (ну, если нужно конечно), вроде


            LANG=C stat . | LANG=C other-command

            • 027
              /#20614039

              Спасибо. А не подскажете, где про это можно почитать? Это же не bash-специфичное поведение?

              • simpleadmin
                /#20614987 / +1

                Это Bourne shell-совместимое поведение.
                Не будет работать в C-shell'ах
                Там потребуется выполнять env, set или setenv соответственно для изменения переменной окружения, установки сессионной переменной и экспорта переменной.

                • eumorozov
                  /#20616145

                  И в fish тоже по другому работает: env LANG=C ls
                  Я уже несколько лет как перешел с bash и zsh на fish. Не знаю откуда у меня такая настойчивость, первые года два ломало, а теперь втянулся и нравится.


                  bash — вообще считаю недоразумением. Сколько лет можно чинить теряющуюся историю?.. Эта проблема существует уже наверное не менее десятилетия. Миллионы хаков напридумано для костыльного исправления этой ошибки, вышел один или два мажорных релиза bash, а воз и ныне там...

                  • Oxyd
                    /#20617607

                    А zsh-то в чём провинился?

                    • eumorozov
                      /#20617669

                      Не знаю, просто мне он всегда как-то не нравился. Не по какой-то конкретной причине, просто идиосинкразия какая-то. Не нравится и все, не могу объяснить.

                  • 027
                    /#20621841

                    Я уже несколько лет как перешел с bash и zsh на fish. Не знаю откуда у меня такая настойчивость, первые года два ломало, а теперь втянулся и нравится.

                    Два года? Похоже, эта ваша рыба заливная! :)

                    • eumorozov
                      /#20624855

                      Честно говоря, единственная вещь, которая напрягала эти два года — отсутствие Ctrl-R в fish. Точнее, неточная эмуляции этого механизма при помощи fzf.


                      Когда работаешь с bash где-то с 1996 года, всякие bash'евские приемы работы начинают жить где-то уже в пальцах. Но два года оказалось достаточно, чтобы перебить старые привычки.


                      Все-такие fish — это какой-то шаг вперед. bash и zsh кажутся отставшими от времени и слишком эклектичными. PowerShell кажется наоборот очередным неудобным overengineering от Microsoft.


                      fish ­— этакий разумный компромисс между эклектичной олдфажностью и современностью.

            • 027
              /#20615169

              Хм… А почему вот это не работает?

              $ LANG=C echo $LANG
              ru_RU.UTF-8
              

              $ LANG=C /bin/echo $LANG
              ru_RU.UTF-8
              

              • POPSuL
                /#20615233

                Потому что $LANG это переменная, которая уже объявлена, и при выполнении этой команды она "разворачивается" в значение ru_RU.UTF-8.


                upd: именно поэтому я и показал пример с getenv

                • 027
                  /#20615459

                  Потому что $LANG это переменная, которая уже объявлена, и при выполнении этой команды она «разворачивается» в значение ru_RU.UTF-8.

                  Как же так? Я ее только что переопределил из 'ru_RU.UTF-8' в 'C'.
                  Почему-то echo это игнорирует, а вот, скажем, man, radeontop используют значение 'C'.

                  • POPSuL
                    /#20615505

                    Потому-что в баше переменные "разворачиваются" в значение до запуска самой программы. По схожему принципу и работает glob, т.е. вы напишете cat *, но баш на самом деле сам прочитает содержимое директории, и выполнит что-то вроде cat a.txt b.txt c.txt somedir.
                    Почему radeontop работает — я не знаю, возможно он работает совсем не так как вы ожидаете, и просто не замечаете это (я за зеленых, поэтому такие тулзы ни разу в жизни не использовал).

                  • simpleadmin
                    /#20615619 / +1

                    Почему-то echo это игнорирует

                    Именно так, потому что echo не «интересуют» переменные окружения.
                    Пример
                    EDITOR=mcedit crontab -e
                    откроет cron в mcedit
                    EDITOR=vi crontab -e
                    откроет cron в vi
                    но
                    $ EDITOR=vi echo "one: [$EDITOR]"
                    one: []

                    echo просто пофиг на нашу переменную окружения.
                    Но мы можем задать её как переменную оболочки и ограничить область действия (Bourne shell-совместимое поведение):
                    $ (EDITOR=vi; echo "one: [$EDITOR"]); echo "two: [$EDITOR]"
                    one: [vi]
                    two: []

                    аналогично для запрашиваемого примера:
                    $ (LANG=C; /bin/echo $LANG); /bin/echo $LANG
                    C
                    en_US.UTF-8


                    • 027
                      /#20616061

                      Именно так, потому что echo не «интересуют» переменные окружения.

                      Я понял так, что модифицированные переменные окружения выдаются программе в виде копии и исключительно для нужд настройки поведения.
                      $LANG интерпретатор берет из текущего окружения для всего сеанса ( а echo тут вообще ничего не решает).
                      Если бы удалось заставить echo ругаться на что-либо, тогда модифицированное значение переменной LANG влияло бы на язык сообщений. Как это и происходит в моей системе с man, nmap и radeontop, которые обучены русскому.

                      Трюк, походу, не bash-специфичный — в dash переключение языка срабатывает.

                      • eumorozov
                        /#20616181

                        echo — встроенная команда bash (builtin). То есть, при выполнении echo не будет порожден новый процесс, в котором будет запущена программа /bin/echo.


                        LANG=C влияет на порожденные процессы. Например, LANG=C ls приводит к порождению процесса запускающего /bin/ls, и в этом процессе уже будет модифицированное окружение.

                        • 027
                          /#20616325

                          echo — встроенная команда bash (builtin). То есть, при выполнении echo не будет порожден новый процесс, в котором будет запущена программа /bin/echo.

                          Я приводил в исходном каменте оба варианта, со встроенным эхом и с /bin/echo. Поведение одинаковое.

                          встроенная команда bash… не будет порожден новый процесс

                          Вы это точно знаете или предполагаете?

                          • 027
                            /#20616365

                            Кстати, подляна изрядная, эти одноименные встроенные команды. Когда не знаешь об этом, массу времени можно потерять, ругая ни в чем не повинного составителя мана утилиты.

                          • eumorozov
                            /#20616385

                            Ах, да, прав комментатор про то, что bash подставляет значения переменных при вызове. Конечно, когда мы пишем cmd $VAR любой shell обязан подставить $VAR до вызова команды.


                            Вы это точно знаете или предполагаете?

                            Конечно уверен. На то они и builtins, к чему тратить ресурсы системы на порождение нового процесса?..


                            Поэтому при отладке каких-то проблем со скриптами и т.п., что я делаю первым делом — запускаю type ls или type cat и т.д., чтобы знать точно, что не имею дело с алиасом или командой, которая взялась не из стандартного пути.

                            • 027
                              /#20616423

                              Конечно уверен. На то они и builtins, к чему тратить ресурсы системы на порождение нового процесса?..

                              Уверенность на основе рассуждения есть предположение. :) Ну да бог с ним. Дело тут совсем не в отдельности процесса.

                              Ах, да, прав комментатор про то, что bash подставляет значения переменных при вызове. Конечно, когда мы пишем cmd $VAR любой shell обязан подставить $VAR до вызова команды.

                              Отож! Он идет по строке справа налево, натыкается на $LANG, рожает указатель (наверное, я в сях не силен) и тупо скармливает его эху. До модифицированного одноразового окружения ему дела нет.
                              А внешне кажется, что это эхо игнорирует, зараза такая своенравная. :)

                              • eumorozov
                                /#20616455

                                Уверенность на основе рассуждения есть предположение. :) Ну да бог с ним. Дело тут совсем не в отдельности процесса.

                                Ну, если бы shell не использовал builtins, то, например, такая команда как cd не имела бы смысла: она бы меняла только текущий каталог порожденного процесса, и в shell не было бы никакой возможности перейти в другой каталог.


                                А так полагаю, что существует много нюансов. Когда-то я целиком читал документацию по bash. Но это было наверное 20 лет назад, и много мелких нюансов я уже забыл. Возможно, для каких-то команд builtins используются только в интерактивном режиме. Беглый просмотр man bash по диагонали не дал подтверждения, надо внимательно читать его целиком, а он огромный.

                            • 027
                              /#20616463

                              запускаю type ls или type cat и т.д., чтобы знать точно, что не имею дело с алиасом или командой, которая взялась не из стандартного пути.

                              Кстати, есть оч. полезная команда в баше:
                              compgen -c will list all the commands you could run.
                              compgen -a will list all the aliases you could run.
                              compgen -b will list all the built-ins you could run.
                              compgen -k will list all the keywords you could run.
                              compgen -A function will list all the functions you could run.
                              compgen -A function -abck will list all the above in one go.

                              В частности, вот так можно отловить дублирующуюся команду:
                              $ compgen -c | grep -E '^time$'
                              time
                              time

                              Попалась, зараза!

                              • simpleadmin
                                /#20616927

                                $ type -a time
                                time is a shell keyword
                                time is /usr/bin/time
                                

                                • 027
                                  /#20616943

                                  О!
                                  Сенькс.
                                  Неисчислимы заковыристые ходы, придуманные в те давние времена, когда компьютеры были большими, а сообщество маленьким.
                                  Множество частных, подробно ориентированных штучек-дрючек, и никто не ведал, что скоро придет диавол под личиной multimedia, и пожрет все, до чего дотянется мягкими, липкими, необъятными в своих слоях абстракций лапищами…

                        • MaxVetrov
                          /#20616399

                          у меня echo — файл в bin

                          • eumorozov
                            /#20616419

                            Да, она есть во всех системах из каких-то соображений. Полагаю, чтобы в пользовательских программах не ломался код типа:
                            system("echo Hello world").


                            Но в shell запустится builtin. /bin/echo запустится, только если писать полный путь: /bin/echo Hello world.

                            • 027
                              /#20616487

                              Да, она есть во всех системах из каких-то соображений. Полагаю, чтобы в пользовательских программах не ломался код типа:
                              system("echo Hello world").

                              Если в путях есть /bin ничего не сломается. А так должно быть обязательно. Ну, если это не наколенная эмбедовка от васяна, понятно.

                              Соображения я встечал такое: большее быстродействие и меньший жор. Вызов внешней утилиты в любом случае накладно. К тому же встроенные нередко более убогие и потому скоростные.

                            • MaxVetrov
                              /#20616631

                              Действительно ,)
                              Для printf, kill, pwd, test — тоже самое.

                              Команды делаются встроенными либо из соображений производительности — встроенные команды исполняются быстрее, чем внешние, которые, как правило, запускаются в дочернем процессе, либо из-за необходимости прямого доступа к внутренним структурам командного интерпретатора.

                          • 027
                            /#20616515

                            у меня echo — файл в bin

                            У меня и то, и другое:
                            $ compgen -c | grep -E '^echo$'
                            echo
                            echo
                            
                            $ which echo
                            /bin/echo
                            
                            $ type echo
                            echo — это встроенная команда bash

                            • MaxVetrov
                              /#20616799

                              возможно, было бы удобно их с индексом запускать:
                              echo[0]
                              echo[1]

                              • 027
                                /#20616811

                                Это как?

                                • MaxVetrov
                                  /#20617285

                                  Я имею ввиду, если бы баш позволял.
                                  [0] — внутренняя
                                  [1] — внешняя
                                  Ключевое слово — возможно.

                                  Хотя есть команда command -p

                                  • eumorozov
                                    /#20617671

                                    Shell и так позволяет запускать любой вариант, было бы странно иначе.
                                    Просто echo — запускает builtin. /bin/echo запускает /bin/echo.


                                    Если кто-то или что-то переопределило echo, то builtin echo явно запустит builtin.

  19. lorc
    /#20612083

    git init . ; git status

    Будет немного лишнего, но можно отфильтровать.

    • 027
      /#20613111

      Чуток поправлю.

      git init . ; git status; rm -rf .git

  20. klirichek
    /#20612119 / +1

    Очень простая, но реальная задача:
    веб-камера с записью "сошла с ума" и вместо записи по движению скинула на флэшку непрерывную запись целой недели. ~20 тыс. файлов. ФС fat32.
    ls (просто) в папке DCIM ничего не выводит (думает минут 5, потом убивается системой).
    И вот тут выясняется, что ls написан внутри очень неплохо! Он не получает "список всего", а потом накладывает фильтр, а сразу фильтрует при выводе на экран. В итоге ls "20190901*" и т.д. вполне сработали! (последующий rm так же сработал по тому же паттерну)

    • alhimik45
      /#20612411

      Только это не ls и rm такие крутые, а шелл, который развернул имя со звездочкой в список файлов и уже их передал списком аргументов (и тут кстати можно словить ошибку, если файлов больше, чем максимально разрешенное число аргументов командной строки)

      • 027
        /#20612549

        Двойные кавычки спасут отца русской демократии, как в примере выше.

    • azmar
      /#20612539

      Рекомендую вам использовать утилиту find в подобных случаях.

  21. Cheater
    /#20612127 / +1

    Даём команду на интерактивное удаление /home/username (rm -i), и генерируем для неё "интерактивный" ответ сначала из одного "y" (для подтверждения рекурсивного спуска в ~), и затем в цикле "n" (для отказа рекурсивного спуска на более нижние уровни и отказа удаления):


    (echo y; yes n) | rm -ir ~

    Улучшенный вариант с последующей чисткой лога от ненужного текста:


    (echo y; yes n) | rm -ir ~ 2>&1 | sed -E -e "s/(rm:[^']+)|\?//g"

    • Cheater
      /#20612197

      Upd: Извиняюсь, проглядел такое же решение в более раннем комменте под спойлером

      • Oxyd
        /#20613015

        Зато sed ещё пока никто не использовал. ;-)

  22. facha
    /#20612229

    hdfs dfs -ls

  23. 027
    /#20612385 / +1

    без использования ls

    «Ты видишь суслика? И я не вижу.»
    $'\x6c\x73' $'\x2d\x61'

  24. Uzix
    /#20612605

    Для FreeBSD:

    cat ~ |strings |xargs -IX sh -c 'test -e X && echo X'

    Но не работает с каталогами и файлами, содержащими в имени перевод строки.

  25. Neveil
    /#20612607

    lsattr ~/* 2>&1 | grep -Po '/.*'

  26. iig
    /#20612615

    printf "%s\n" *
    

  27. Jungo
    /#20612623

    rm -rfv ./*

    • Oxyd
      /#20612973

      На хабре бывают и менее опытные пользователи, чем мы с вами. Могут и не распознать патч Бармина, в миниатюре. ;-)

      • 027
        /#20613037 / +1

        Все нормально. Так учатся плавать щенки закаляется сталь становятся на ноги тру-линуксоиды.

  28. gudvinr
    /#20612887

    python -m http.server > /dev/null & export PID=$(echo $!) && sleep 1 && curl -s localhost:8000/ | grep -Po '(?<=href=")[^"]*' && kill $PID

    Если вы оказались в сложной жизненной ситуации и у вас есть только Go:


    cat <<EOF | tee /tmp/habr.go | go run /tmp/habr.go
    package main; import ("fmt"; "path/filepath"); func main() {f,_ := filepath.Glob("*"); fmt.Println(f)}
    EOF

    Аналогично, для поклонников современного C++:


    cat <<EOF | c++ -x c++ --std=c++17 -o /tmp/habr - && /tmp/habr
    #include <iostream>
    #include <filesystem>
    using namespace std;
    int main() { for (auto e : filesystem::directory_iterator(".")) cout<<e.path()<<endl; }
    EOF

  29. ne_zabudka
    /#20613227

    compgen -f

    без скрытых файлов
    shuf -e *

    • MaxVetrov
      /#20617131 / +1

      со скрытыми файлами

      shuf -e * .*

  30. ne_zabudka
    /#20613911

    справедливо для gawk

    (shopt -s dotglob; awk -lreaddir 'ENDFILE {print FILENAME}' *)

  31. MaxVetrov
    /#20614349

    mkdir aaa && mv -v ~/* ~/.* aaa && mv aaa/*. aaa/* ~ && rm -r aaa

    • POPSuL
      /#20614373

      Тогда уж проще заюзать cp -alv вместо mv, и безопаснее.

      • MaxVetrov
        /#20615727

        Проще использовать ls :)
        mv — быстрее выполняется

  32. iig
    /#20614441 / +1

    firefox file://$PWD

    • POPSuL
      /#20614479

      Ну, так сходу наверное не получится, firefox скажет "давай мне иксы", но вот такой способ:


      chromium-browser --headless --no-sandbox --disable-gpu --dump-dom file:///$HOME | awk -F'"' '{print $2}'

      вполне имеет право на жизнь!
      Oxyd думаю можно во вторую статью добавить ;)

      • 027
        /#20614585 / +1

        От извращенцы!
        (одобряэ)

      • Oxyd
        /#20617599 / +1

        О Да!!! (побежал ставить Chromium)

  33. MaxVetrov
    /#20617529

    mc
    ranger
    exa

    wc -c *
    size *
    cksum *
    crc32 *
    sha1sum *
    md5sum *
    sum *
    

    Осторожно .)
    chmod -v -x *
    chown -v <user> *
    strip -v *