V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
wniming
V2EX  ›  Linux

如何把 pgrep 输出结果中需要用单引号包起来的参数包起来?

  •  
  •   wniming · 5 天前 · 930 次点击

    比如有如下 qemu 的命令行:

    qemu-system-x86_64 \
    -machine q35,accel=kvm \
    -cpu host \
    -m 1G \
    -kernel /home/d/kernel/kernel \
    -initrd /home/d/rd/initramfs.cpio.gz \
    -append 'console=ttyS0 test="11 22"' \
    -netdev '{"type":"tap","vhost":true,"ifname":"eth_0","id":"hostnet0","script":"","downscript":""}' \
    -device '{"driver":"virtio-net-pci","netdev":"hostnet0","id":"net0","mac":"52:54:00:c0:45:c7"}' \
    -nographic
    
    

    上述命令的参数的格式是有效的,但是如果命令执行后通过 pgrep 查询命令行字符串,查询出的结果会把单引号去掉:

    d@develop:~$ pgrep -af qemu-system-x86_64 | perl -0pe 's/ -/ \\\n-/g'
    19754 qemu-system-x86_64 \
    -machine q35,accel=kvm \
    -cpu host \
    -m 1G \
    -kernel /home/d/kernel/kernel \
    -initrd /home/d/rd/initramfs.cpio.gz \
    -append console=ttyS0 test="11 22" \
    -netdev {"type":"tap","vhost":true,"ifname":"eth_0","id":"hostnet0","script":"","downscript":""} \
    -device {"driver":"virtio-net-pci","netdev":"hostnet0","id":"net0","mac":"52:54:00:c0:45:c7"} \
    -nographic
    
    

    去掉单引号的命令无法直接放到 shell 里去执行,我想找到一个通用的办法(不要仅限于 qemu 的参数)把 pgrpe 输出的命令行字符串中需要用单引号包起来的参数用单引号包起来,使其结果和最初执行的命令行字符串完全一样,问了 ai ,ai 解决不了,再次在这里求助 v 友。

    第 1 条附言  ·  4 天前

    #7 楼给出的方法管用,这里备份一下:

    #!/usr/bin/env python3
    import sys
    import shlex
    
    
    def get_cmdline(pid):
        with open(f"/proc/{pid}/cmdline") as f:
            raw = f.read()
        parts = raw.strip("\0").split("\0")
        return shlex.join(parts)
    
    
    def main():
        if len(sys.argv) != 2:
            print(f"Usage: {sys.argv[0]} <pid>", file=sys.stderr)
            sys.exit(1)
        pid = sys.argv[1]
        print(get_cmdline(pid))
    
    
    if __name__ == "__main__":
        main()
    
    11 条回复    2025-07-28 09:44:20 +08:00
    julyclyde
        1
    julyclyde  
       4 天前
    你去/proc/pid/cmdline 里边按照\0 重新组装一下命令行吧
    wniming
        2
    wniming  
    OP
       4 天前
    @julyclyde 能具体一点吗?我想当伸手党。。。。

    我自己简单研究了一下,你说的这种方法和 pgrep 没有什么区别:

    d@develop:~$ cat /proc/19754/cmdline | xargs -0 echo | perl -0pe 's/ -/ \\\n-/g'
    qemu-system-x86_64 \
    -machine q35,accel=kvm \
    -cpu host \
    -m 1G \
    -kernel /home/d/kernel/kernel \
    -initrd /home/d/rd/initramfs.cpio.gz \
    -append console=ttyS0 test="11 22" \
    -netdev {"type":"tap","vhost":true,"ifname":"eth_0","id":"hostnet0","script":"","downscript":""} \
    -device {"driver":"virtio-net-pci","netdev":"hostnet0","id":"net0","mac":"52:54:00:c0:45:c7"} \
    -nographic
    julyclyde
        3
    julyclyde  
       4 天前
    @wniming 其实按说你可以无脑把里边每个字段都加上引号吧?

    你下一步打算怎么使用这个内容?
    billlee
        4
    billlee  
       4 天前
    别用 shell 了,用 python 调 os.execvp, 把参数用数组的形式传进去,就不需要引号和转义。
    wniming
        5
    wniming  
    OP
       4 天前
    @julyclyde #3 是的,最简单的方式就是每个选项和参数都用单引号包起来,但是这样不美观,我是想把命令行存到日志文件里,就像 libvirt 那样,libvirt 就把日志里的 qemu 命令行格式化成了我想要的效果:

    /usr/bin/qemu-system-x86_64 \
    -name guest=win11-23h2,debug-threads=on \
    -S \
    -object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain-9-win11-23h2/master-key.aes"}' \
    -blockdev '{"driver":"file","filename":"/usr/share/edk2/ovmf/OVMF_CODE_4M.qcow2","node-name":"libvirt-pflash0-storage","auto-read-only":true,"discard":"unmap"}' \
    -blockdev '{"node-name":"libvirt-pflash0-format","read-only":true,"driver":"qcow2","file":"libvirt-pflash0-storage","backing":null}' \
    -blockdev '{"driver":"file","filename":"/var/lib/libvirt/qemu/nvram/win11-23h2_VARS.qcow2","node-name":"libvirt-pflash1-storage","auto-read-only":true,"discard":"unmap"}' \
    -blockdev '{"node-name":"libvirt-pflash1-format","read-only":false,"driver":"qcow2","file":"libvirt-pflash1-storage","backing":null}' \
    -machine pc-q35-8.2,usb=off,vmport=off,smm=on,dump-guest-core=off,memory-backend=pc.ram,pflash0=libvirt-pflash0-format,pflash1=libvirt-pflash1-format,hpet=off,acpi=on \
    -accel kvm \
    -cpu host,migratable=on,host-phys-bits=on,host-phys-bits-limit=39 \
    -m size=16777216k \
    -object '{"qom-type":"memory-backend-memfd","id":"pc.ram","hugetlb":true,"hugetlbsize":1073741824,"share":true,"x-use-canonical-path-for-ramblock-id":false,"prealloc":true,"size":17179869184}' \
    -overcommit mem-lock=off \
    -smp 8,sockets=1,dies=1,clusters=1,cores=8,threads=1 \
    -uuid a7849adb-a74b-4086-a0a6-738c5e689a8a \
    -no-user-config \
    -nodefaults \
    -chardev socket,id=charmonitor,fd=23,server=on,wait=off \
    -mon chardev=charmonitor,id=monitor,mode=control \
    -rtc base=utc,driftfix=slew \
    -global kvm-pit.lost_tick_policy=delay \
    -no-shutdown \
    -global ICH9-LPC.disable_s3=1 \
    -global ICH9-LPC.disable_s4=1 \
    -boot menu=on,strict=on \
    -device '{"driver":"pcie-root-port","port":16,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x2"}' \
    -device '{"driver":"pcie-root-port","port":17,"chassis":2,"id":"pci.2","bus":"pcie.0","addr":"0x2.0x1"}' \
    -device '{"driver":"pcie-root-port","port":18,"chassis":3,"id":"pci.3","bus":"pcie.0","addr":"0x2.0x2"}' \
    -device '{"driver":"pcie-root-port","port":19,"chassis":4,"id":"pci.4","bus":"pcie.0","addr":"0x2.0x3"}' \
    -device '{"driver":"pcie-root-port","port":20,"chassis":5,"id":"pci.5","bus":"pcie.0","addr":"0x2.0x4"}' \
    -device '{"driver":"pcie-root-port","port":21,"chassis":6,"id":"pci.6","bus":"pcie.0","addr":"0x2.0x5"}' \
    -device '{"driver":"pcie-root-port","port":22,"chassis":7,"id":"pci.7","bus":"pcie.0","addr":"0x2.0x6"}' \
    -device '{"driver":"pcie-root-port","port":23,"chassis":8,"id":"pci.8","bus":"pcie.0","addr":"0x2.0x7"}' \
    -device '{"driver":"pcie-root-port","port":24,"chassis":9,"id":"pci.9","bus":"pcie.0","multifunction":true,"addr":"0x3"}' \
    -device '{"driver":"pcie-root-port","port":25,"chassis":10,"id":"pci.10","bus":"pcie.0","addr":"0x3.0x1"}' \
    -device '{"driver":"pcie-root-port","port":26,"chassis":11,"id":"pci.11","bus":"pcie.0","addr":"0x3.0x2"}' \
    -device '{"driver":"pcie-root-port","port":27,"chassis":12,"id":"pci.12","bus":"pcie.0","addr":"0x3.0x3"}' \
    -device '{"driver":"pcie-root-port","port":28,"chassis":13,"id":"pci.13","bus":"pcie.0","addr":"0x3.0x4"}' \
    -device '{"driver":"pcie-root-port","port":29,"chassis":14,"id":"pci.14","bus":"pcie.0","addr":"0x3.0x5"}' \
    -device '{"driver":"pcie-root-port","port":8,"chassis":15,"id":"pci.15","bus":"pcie.0","addr":"0x1"}' \
    -device '{"driver":"pcie-pci-bridge","id":"pci.16","bus":"pci.12","addr":"0x0"}' \
    -device '{"driver":"qemu-xhci","p2":15,"p3":15,"id":"usb","bus":"pci.2","addr":"0x0"}' \
    -device '{"driver":"virtio-scsi-pci","id":"scsi0","bus":"pci.7","addr":"0x0"}' \
    -device '{"driver":"virtio-serial-pci","id":"virtio-serial0","bus":"pci.3","addr":"0x0"}' \
    -blockdev '{"driver":"host_device","filename":"/dev/thin/win11_23h2","aio":"native","node-name":"libvirt-1-storage","read-only":false,"discard":"unmap","cache":{"direct":true,"no-flush":false}}' \
    -device '{"driver":"virtio-blk-pci","bus":"pci.4","addr":"0x0","drive":"libvirt-1-storage","id":"virtio-disk0","bootindex":1,"write-cache":"on"}' \
    -netdev '{"type":"tap","fd":"24","vhost":true,"vhostfd":"32","id":"hostnet0"}' \
    -device '{"driver":"virtio-net-pci","netdev":"hostnet0","id":"net0","mac":"52:54:00:1a:14:2d","bus":"pci.1","addr":"0x0"}' \
    -netdev '{"type":"tap","fd":"33","vhost":true,"vhostfd":"34","id":"hostnet1"}' \
    -device '{"driver":"virtio-net-pci","netdev":"hostnet1","id":"net1","mac":"52:54:00:e1:84:76","bus":"pci.11","addr":"0x0"}' \
    -chardev spicevmc,id=charchannel0,name=vdagent \
    -device '{"driver":"virtserialport","bus":"virtio-serial0.0","nr":2,"chardev":"charchannel0","id":"channel0","name":"com.redhat.spice.0"}' \
    -chardev socket,id=charchannel1,fd=22,server=on,wait=off \
    -device '{"driver":"virtserialport","bus":"virtio-serial0.0","nr":1,"chardev":"charchannel1","id":"channel1","name":"org.qemu.guest_agent.0"}' \
    -audiodev '{"id":"audio1","driver":"spice"}' \
    -spice port=5900,addr=0.0.0.0,disable-ticketing=on,image-compression=off,seamless-migration=on \
    -global ICH9-LPC.noreboot=off \
    -watchdog-action reset \
    -chardev spicevmc,id=charredir0,name=usbredir \
    -device '{"driver":"usb-redir","chardev":"charredir0","id":"redir0","bus":"usb.0","port":"2"}' \
    -chardev spicevmc,id=charredir1,name=usbredir \
    -device '{"driver":"usb-redir","chardev":"charredir1","id":"redir1","bus":"usb.0","port":"3"}' \
    -chardev spicevmc,id=charredir2,name=usbredir \
    -device '{"driver":"usb-redir","chardev":"charredir2","id":"redir2","bus":"usb.0","port":"4"}' \
    -chardev spicevmc,id=charredir3,name=usbredir \
    -device '{"driver":"usb-redir","chardev":"charredir3","id":"redir3","bus":"usb.0","port":"5"}' \
    -device '{"driver":"vfio-pci","host":"0000:08:00.0","id":"hostdev0","bus":"pci.5","addr":"0x0","romfile":"/home/d/.local/share/libvirt/rom/Navi_23.rom"}' \
    -device '{"driver":"vfio-pci","host":"0000:08:00.1","id":"hostdev1","bus":"pci.8","addr":"0x0"}' \
    -object '{"qom-type":"rng-random","id":"objrng0","filename":"/dev/urandom"}' \
    -device '{"driver":"virtio-rng-pci","rng":"objrng0","id":"rng0","bus":"pci.6","addr":"0x0"}' \
    -device '{"driver":"usb-host","hostbus":1,"hostport":"7","bus":"usb.0"}' \
    -device '{"driver":"usb-host","hostbus":1,"hostport":"11","bus":"usb.0"}' \
    -device '{"driver":"usb-host","hostbus":1,"hostport":"10.4","bus":"usb.0"}' \
    -device '{"driver":"usb-host","hostbus":1,"hostport":"10.2","bus":"usb.0"}' \
    -sandbox off \
    -msg timestamp=on

    只把需要用单引号包起来的参数用单引包起来。
    wniming
        6
    wniming  
    OP
       4 天前
    @billlee 我是想把 qemu 的命令行保存到文件里
    sunfkny
        7
    sunfkny  
       4 天前   ❤️ 1
    https://gist.github.com/sunfkny/90f4a99c7444a840bb5f651c758a38f3
    还得是 python, 核心就是\0 分割 cmdline 之后 shlex.join
    wniming
        8
    wniming  
    OP
       4 天前
    @sunfkny 谢谢,完美解决
    billlee
        9
    billlee  
       4 天前
    @wniming 只用单引号包起来是不能处理所有情况的,因为参数里可能本身就有单引号。如果需求只是“保存”,那按照 /proc/$pid/cmdline 原样保存就行了。如果其实你需要的是转换成 shell 格式,那需要遍历每个参数,对参数做 shell escape
    guanzhangzhang
        10
    guanzhangzhang  
       4 天前
    xargs -0 /proc/<pid>/cmdline > result.txt
    guanzhangzhang
        11
    guanzhangzhang  
       4 天前
    @guanzhangzhang xargs -0 < /proc/<pid>/cmdline > result.txt
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5128 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 08:40 · PVG 16:40 · LAX 01:40 · JFK 04:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.