Как показать список цитируемых команд?

ps -o command показывает каждую команду на отдельной строке с разделенными пробелами, аргументами без кавычек:

 $ ps -o command COMMAND bash ps -o command 

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

 $ xss-lock --notifier="notify-send -- 'foo bar'" slock & [1] 20172 $ ps -o command | grep [x]ss-lock xss-lock --notifier=notify-send -- 'foo bar' slock 

Результат ps вводит в заблуждение – если вы попытаетесь скопировать и вставить его, команда не будет делать то же самое, что и оригинал. Итак , есть способ, похожий на printf %q Bash, распечатать список запущенных команд с правильно экранированными или кавычками аргументами ?

3 Solutions collect form web for “Как показать список цитируемых команд?”

В Linux вы можете получить немного более сырой список аргументов команды из /proc/$pid/cmdline для данного идентификатора процесса. Аргенты разделяются нулем. Попробуйте cat -v /proc/$pid/cmdline чтобы увидеть nuls как ^@ , в вашем случае: xss-lock^@--notifier=notify-send -- 'foo bar'^@slock^@ .

Следующий скрипт perl может прочитать файл proc и заменить nuls на новую строку и вкладку для вашего примера:

 xss-lock --notifier=notify-send -- 'foo bar' slock 

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

 xss-lock '--notifier=notify-send -- '\''foo bar'\''' 'slock' 

если вы замените if(1) на if(0) :

 perl -e ' $_ = <STDIN>; if(1){ s/\000/\n\t/g; s/\t$//; # remove last added tab }else{ s/'\''/'\''\\'\'\''/g; # escape all single quotes s/\000/ '\''/; # do first nul s/(.*)\000/\1'\''/; # do last nul s/\000/'"' '"'/g; # all other nuls } print "$_\n"; ' </proc/$pid/cmdline 

Как отметил meuh, вы можете получить строку в Linux и NetBSD из /proc/PID/cmdline с аргументами, ограниченными байтами NUL. Вот быстрый и грязный способ превратить их в исполняемые командные строки.

 perl -ne 'print join(" ", map quotemeta, split(/\000/)), "\n"' /proc/.../cmdline 

Результат выглядит так:

 xss\-lock \-\-notifier\=notify\-send\ \-\-\ \'foo\ bar\' slock 

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

Более короткий вариант (требуется Perl 5.10 или новее):

 perl -nE '$, = " "; say map quotemeta, split /\0/' /proc/.../cmdline 

И пока я нахожусь, версия для гольфа (40 байт):

 perl -nE'$,=" ";say map"\Q$_",split/\0/' /proc/.../cmdline 

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


 ps -ocommand | grep \[x]ss-lock 

… сначала напечатает серию запущенных командных строк процесса, а затем отфильтрует этот список только для тех, которые соответствуют регулярному выражению \[x]ss-lock . используемый в регулярном выражении \[x]... является довольно распространенной xss-lock для обработки гонки результатов, связанной с перечислением множества процессов с именем xss-lock путем фильтрации другого списка с помощью команды, содержащей слова xss-lock .

это не лучший способ сделать это. система ps linux обычно является procps-ng ps которая поддерживает фильтр -C ommand name, который, как мне сказали, вероятно, возник из-за ps AIX.

в любом случае вы можете отбросить часть гонки, например:

 ps -C xss-lock -ocommand 

… печатать только те командные строки для запуска процессов, если имя команды (которое вы также можете ps -Aocomm= как ps -Aocomm= ) полностью соответствует xss-lock – как это может сделать фильтр grep -Fx . для фактического фильтрации с помощью регулярных выражений существует также инструмент pgrep , который может выполнять аналогичное сопоставление регулярных выражений без гонок.


eponymously, procps-ng ps работает путем анализа файлов в дереве /proc . для вашего ps -ocommand , например, он читает файл /proc/$pid/cmdline для каждого совпадения, который он должен печатать, и заменяет \0 NUL s (меньше последнего – который вместо этого становится \n ewline) (который ограничивает каждый аргумент в файле) с пробелом каждый.

если вам нужны списки аргументов с кодами, вы должны будете сделать подобное. самый простой способ передать цитату любому списку – сделать это с помощью ' жестких кавычек». это очень просто, потому что строка с твердым кавычком всегда плоская – в синтаксическом анализе нет рекурсии глубины, потому что строка с твердой кавычкой не может содержать другую жесткую цитату. так…

 'it'\''s not a single string' 

… не является одной строкой с кавычками, а является тремя конкатенированными строками. во-первых, it окружен с обеих сторон жесткими кавычками; второй – это одиночный апостроф с обратным пространством; а третья, а не одна строка , жестко цитируется как первая. оболочка объединяет все три кавычки в одно слово оболочки при разборе.

мы можем сделать то же самое с файлом /proc/$pid/cmdline . нам нужно разбить каждый файл на \0 байт NUL , предкапить каждый найденный там апостроф, как '\'' , а затем окружить каждый объект апострофами и вставить один или несколько символов \t ab или пробел между ними.

теперь, когда я думаю об этом, моя первая версия этого была без лишних усилий и, как результат, фактически подвержена ошибкам. интуитивно я попытался скомпрометировать аргументы каждой команды, поэтому все объекты для одного /proc/$pid/file меньше первого, но это не работает (и, фактически, полностью инвертирует всю итоговую цитату из командной строки, level), если имя команды содержит нечетное число апострофов. и в любом случае это не имеет значения – 'cat' работает так же хорошо, как и cat когда запускается в командной строке. на самом деле, он работает лучше, потому что первым гораздо вероятнее будет cat найденная в /proc/$pid/file чем в противном случае, если интерпретации shell-алиасов (как это было бы с cat ) .


поэтому я сделал аналогичную вещь для Perl скрипта meuh, но с инструментами GNU. в частности, опция sed -z инструктирует GNU sed разделить ввод на \0 NUL байтах, а не на \n ewlines, а его параметр -s указывает обрабатывать каждый аргумент файла как отдельный поток ввода (так что последняя строка может быть индивидуально ссылаются на каждый аргумент и H старое пространство повторно инициализируется для каждого) . ps -Csh -opid= печатает один номер pid в строке для каждого выполняющегося процесса, соответствующего имени команды sh , и sed "s|$|/cmdline|" просто добавляет это имя пути каждому.

потому что $IFS не $(cmdsub's) вывод $(cmdsub's) определенно будет разделен оболочкой на отдельные аргументы в белом пространстве – это всего лишь одна строка \n ewline для каждого имени пути, а процесс sed -sze получает список аргументов всех из путей /proc/$pid/cmdline которые существовали в то время, когда ps -C искал их. этот последний бит повторно вводит всю игру в гонку, что видно из сообщения об ошибке, напечатанного, когда sed -sze пытается прочитать файл cmdline для процесса команды sub sh который больше не существует, поскольку он ушел с момента, когда sed -sze вообще называется.


 sh -c ' cd /proc; unset IFS sed -sze "H;1h;$"\!"d;x" \ -e "s/$1/&\\\\&&/g" \ -e "s/\x00/$1 $1/g" \ -e "s/.*/$1&$1\n/" \ $( ps -Csh -opid= | sed "s|$|/cmdline|") /dev/null ' -- \' 

 './sh' '-IE' 'sh' './sh' '-E' '../sh' 'sh' '-c' ' cd /proc; unset IFS sed -sze "H;1h;$"\!"d;x" \ -e "s/$1/&\\\\&&/g" \ -e "s/\x00/$1 $1/g" \ -e "s/.*/$1&$1\n/" \ $( ps -Csh -opid= | sed "s|$|/cmdline|") /dev/null ' '--' ''\''' 

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

если я удаляю эту последнюю пустую строку ввода и завершаю указанную команду сразу после /dev/null (которая используется для предотвращения процесса sed -sze от захвата stdin в случае отсутствия результатов ps -Csome_process ) , процесс sh -c ( в системе с dash sh ) будет просто exec sed -sze и заменить его на него, а не ждать, чтобы проверить следующую строку ввода. в этом случае sed -sze сможет прочитать свой собственный файл /proc/$pid/cmdline – поскольку он сохраняет /proc/$pid/cmdline файл sh -c :

 sh -c ' cd /proc; unset IFS sed -sze "H;1h;$"\!"d;x" \ -e "s/$1/&\\\\&&/g" \ -e "s/\x00/$1 $1/g" \ -e "s/.*/$1&$1\n/" \ $( ps -Csh -opid= | sed "s|$|/cmdline|") /dev/null' -- \' 

 './sh' '-IE' 'sh' './sh' '-E' '../sh' 'sed' '-sze' 'H;1h;$!d;x' '-e' 's/'\''/&\\&&/g' '-e' 's/\x00/'\'' '\''/g' '-e' 's/.*/'\''&'\''\n/' '2508/cmdline' '3773/cmdline' '5099/cmdline' '26599/cmdline' '31487/cmdline' '31488/cmdline' '31881/cmdline' '/dev/null' sed: can't read 31488/cmdline: No such file or directory 'sh' 

Вот аналогичная версия, но она индивидуально цитирует каждую команду целиком и складывает скрытые кавычки внутри каждого другого слоя глубоко:

 eval "set $( sh -c ' cd /proc; unset IFS sed -sze "H;$"\!"d;x" \ -e "s/$1/$2\\\\$2$2/g" \ -e "s/\x00\([^\x00]*\)/$2\1$2 /g"\ -e "s/.*/$1&$1\\\\\n /" \ $( ps -Csh -opid= | sed "s|$|/cmdline|") /dev/null ' -- \' "'\\\''")" i= for arg do printf "$arg $((i+=1)):\t%s\n" "$arg" done; eval "$5" 

 arg 1: './sh' '-IE' arg 2: 'sh' arg 3: './sh' '-E' arg 4: '../sh' arg 5: 'sh' '-c' ' cd /proc; unset IFS sed -sze "H;$"\!"d;x" \ -e "s/$1/$2\\\\$2$2/g" \ -e "s/\x00\([^\x00]*\)/$2\1$2 /g"\ -e "s/.*/$1&$1\\\\\n /" \ $( ps -Csh -opid= | sed "s|$|/cmdline|") /dev/null ' '--' ''\''' ''\''\\'\'''\''' arg 6: 'sh' ''\''./sh'\'' '\''-IE'\'' '\ ''\''sh'\'' '\ ''\''./sh'\'' '\''-E'\'' '\ ''\''../sh'\'' '\ ''\''sh'\'' '\''-c'\'' '\'' cd /proc; unset IFS sed -sze "H;$"\!"d;x" \ -e "s/$1/$2\\\\$2$2/g" \ -e "s/\x00\([^\x00]*\)/$2\1$2 /g"\ -e "s/.*/$1&$1\\\\\n /" \ $( ps -Csh -opid= | sed "s|$|/cmdline|") /dev/null '\'' '\''--'\'' '\'''\''\'\'''\'''\'' '\'''\''\'\'''\''\\'\''\'\'''\'''\''\'\'''\'''\'' '\ sed: can't read 31725/cmdline: No such file or directory ''\''sh'\'' ' 
  • Асимметричная сессия ESTABLISHED в netstat
  • Завершение скрипта оболочки bash, работающего в фоновом режиме
  • Что означает aux в `ps aux`?
  • Различное представление bash в команде «ps -f»
  • Как заставить команду ps показать память в mb вместо kb?
  • История процессов в системах Unix / Linux
  • Что означает <несуществующий> в выводе ps?
  • Элегантный список детских процессов
  • grep дает результаты, которые не отображаются в исходном контексте
  • Получите обновляющий список запущенных определенных процессов
  • Пожалуйста, объясните этот вывод команды ps -ef?
  • Linux и Unix - лучшая ОС в мире.