原来听领导说过,Linux下目前没有类似python parse 的库,直到最近才发现,项目中有同事用到了此类技术,故在这里进行总结,以方便自己下次使用。
示例代码:
...
#include <getopt.h>
...
struct CommandOptions {
eboolean no_preview;
const echar *streamUrl;
const echar *streamName;
euint deviceId;
XXVideoFormat cameraFormat;
euint videoWidth;
euint videoHeight;
euint framerate;
}; // 需要自定义
...
int main(int argc, char *argv[])
{
//... 初始化代码
struct CommandOptions options = {
.no_preview = FALSE,
.streamUrl = "rtmp://xx/live", // live"
.streamName = "myChannel",
.deviceId = 0,
.cameraFormat = xx_VIDEO_FORMAT_UYVY,
.videoWidth = 1920,
.videoHeight = 1080,
.framerate = DEFAULT_FRAME_RATE
};
static struct option long_options[] = {
{ "streamUrl", required_argument, NULL, 'u' },
{ "streamName", required_argument, NULL, 'n' },
{ "deviceId", required_argument, NULL, 'd' },
{ "camfmt", required_argument, NULL, 'f' },
{ "no-preview", no_argument, NULL, 'p' },
{ "width", required_argument, NULL, 'w' },
{ "height", required_argument, NULL, 'h' },
{ "framerate", required_argument, NULL, 'r' },
{ "help", no_argument, NULL, 'H' },
{ 0, 0, 0, 0 }
};
while (TRUE) {
int c;
int option_index = 0;
c = getopt_long(argc, argv, "u:n:d:f:pw:h:r:H", long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'u':
options.streamUrl = optarg;
break;
case 'n':
options.streamName = optarg;
break;
case 'd':
options.deviceId = atoi(optarg);
break;
case 'p':
options.no_preview = TRUE;
break;
case 'w':
options.videoWidth = atoi(optarg);
break;
case 'h':
options.videoHeight = atoi(optarg);
break;
case 'r':
options.framerate = atoi(optarg);
break;
case 'H':
print_usage(argv[0]);
exit(0);
break;
case 'f':
options.cameraFormat = xx_get_video_format_from_str(optarg);
if (options.cameraFormat == xx_VIDEO_FORMAT_UNKNOWN){
printf("Unknown video format: %s\n", optarg);
print_usage(argv[0]);
exit(-1);
}
break;
case '?':
print_usage(argv[0]);
exit(-1);
break;
default:
printf("?? getopt returned unknown code 0x%x ??\n", c);
print_usage(argv[0]);
exit(-1);
break;
}
}
if (options.streamUrl == NULL || options.streamName == NULL) {
printf("Stream URL and stream name must be specified!\n");
print_usage(argv[0]);
exit(-1);
}
这里,只有getopt_long
是系统调用,需要引入有文件
CS143基础知识; CS243高阶+动手; CS343 读论文
A good place to start is the GCC Wiki Getting Started page: https://gcc.gnu.org/wiki/#Getting_Started_with_GCC_Development
有众多的理由可以让你喜欢编程,那么是什么东西让你坚持这条路的呢?
对于现在我而言,这是一份令我感觉不是那么无聊而且还能领取不错薪水的工作。尽管我向往绝对自由的世界,但是,那种 自由对我来说,太过遥远。
我希望有一天能够: Hack for 纯粹的技术,而不是为了业务而不停的与别人扯皮。
一直都觉得自己在编程方面还是有点欠缺的,也一直鞭策自己不能停下脚本进行学习。
这里,后面还会进行补充。
大家想一想,当你写的代码在遇到一些不明所以的问题时,如何快速的debug呢? GDB是一方面,但是不怎么友好对使用者来说?那还有没有其他的方式呢?
有的,就是log。我们应该把自己写的程序跑过的一些东西,以log的形式保存在 一个特殊的位置,大部分发行版中,大部分位置是 /var/log,也就是如果你确实 找不到一个合适的位置来放置log,那么,这个位置绝对没有问题。
C/C++或者java python等这种强编译型的语言有日志文件比较常见,但是shell也 有log,不知道你之前是否能想到。
下面的代码主要参考这个link。
cat logger.sh
sudo chown $USER:$USER -R /var/log
SCRIPT_LOG=/var/log/SystemOut.log
touch $SCRIPT_LOG
sudo chown $USER:$USER $SCRIPT_LOG
function SCRIPTENTRY(){
timeAndDate=`date`
script_name=`basename "$0"`
script_name="${script_name%.*}"
echo "[$timeAndDate] [DEBUG] > $script_name $FUNCNAME" >> $SCRIPT_LOG
}
function SCRIPTEXIT(){
script_name=`basename "$0"`
script_name="${script_name%.*}"
echo "[$timeAndDate] [DEBUG] < $script_name $FUNCNAME" >> $SCRIPT_LOG
}
function ENTRY(){
local cfn="${FUNCNAME[1]}"
timeAndDate=`date`
echo "[$timeAndDate] [DEBUG] > $cfn $FUNCNAME" >> $SCRIPT_LOG
}
function EXIT(){
local cfn="${FUNCNAME[1]}"
timeAndDate=`date`
echo "[$timeAndDate] [DEBUG] < $cfn $FUNCNAME" >> $SCRIPT_LOG
}
function INFO(){
local function_name="${FUNCNAME[1]}"
local msg="$1"
timeAndDate=`date`
echo "[$timeAndDate] [INFO] $msg" >> $SCRIPT_LOG
}
function DEBUG(){
local function_name="${FUNCNAME[1]}"
local msg="$1"
timeAndDate=`date`
echo "[$timeAndDate] [DEBUG] $msg" >> $SCRIPT_LOG
}
function ERROR(){
local function_name="${FUNCNAME[1]}"
local msg="$1"
timeAndDate=`date`
echo "[$timeAndDate] [ERROR] $msg" >> $SCRIPT_LOG
}
cat test_logger.sh
#!/bin/sh
source ./logger.sh
SCRIPTENTRY
updateUserDetails(){
ENTRY
DEBUG "Username: $1, Key: $2"
INFO "User details updated for $1"
EXIT
}
INFO "Updating user details..."
updateUserDetails "cubicrace" "3445"
rc=2
if [ ! "$rc" = "0" ]
then
ERROR "Failed to update user details. RC=$rc"
fi
SCRIPTEXIT
下面是详细的测试log:
vimer@user-HP:/var/log$ cat SystemOut.log
[2022年 01月 08日 星期六 21:17:23 CST] [DEBUG] > test_logger SCRIPTENTRY
[2022年 01月 08日 星期六 21:17:23 CST] [INFO] Updating user details...
[2022年 01月 08日 星期六 21:17:23 CST] [DEBUG] > updateUserDetails ENTRY
[2022年 01月 08日 星期六 21:17:23 CST] [DEBUG] Username: cubicrace, Key: 3445
[2022年 01月 08日 星期六 21:17:23 CST] [INFO] User details updated for cubicrace
[2022年 01月 08日 星期六 21:17:23 CST] [DEBUG] < updateUserDetails EXIT
[2022年 01月 08日 星期六 21:17:23 CST] [ERROR] Failed to update user details. RC=2
[2022年 01月 08日 星期六 21:17:23 CST] [DEBUG] < test_logger SCRIPTEXIT
[2022年 01月 08日 星期六 21:17:57 CST] [DEBUG] > test_logger SCRIPTENTRY
[2022年 01月 08日 星期六 21:17:57 CST] [INFO] Updating user details...
[2022年 01月 08日 星期六 21:17:57 CST] [DEBUG] > updateUserDetails ENTRY
[2022年 01月 08日 星期六 21:17:57 CST] [DEBUG] Username: cubicrace, Key: 3445
[2022年 01月 08日 星期六 21:17:57 CST] [INFO] User details updated for cubicrace
[2022年 01月 08日 星期六 21:17:57 CST] [DEBUG] < updateUserDetails EXIT
[2022年 01月 08日 星期六 21:17:57 CST] [ERROR] Failed to update user details. RC=2
[2022年 01月 08日 星期六 21:17:57 CST] [DEBUG] < test_logger SCRIPTEXIT
Contains file attributes, metadata of file, pointer structure
Can be considered a table with 2 columns, filename and its inode, inode points to the raw data blocks on the block device
just a special file, container for other filenames. It contains an array of filenames and inode numbers for each filename. Also it describes the relationship between parent and children
On typical ext4 file system (what most people use), the default inode size is 256 bytes, block size is 4096 bytes.
A directory is just a special file which contains an array of filenames and inode numbers. When the directory was created, the file system allocated 1 inode to the directory with a “filename” (dir name in fact). The inode points to a single data block (minimum overhead), which is 4096 bytes. That’s why you see 4096 / 4.0K when using ls.
一个目录仅是一个文件: 包含
You can get the details by using tune2fs & dumpe2fs
systemd-analyze --order
Startup finished in 3.515s (kernel) + 10min 4.683s (userspace) = 10min 8.198s
graphical.target reached after 10min 4.623s in userspace
然后可以看到我们的graphical.target已经达到了10min,这个是无法忍受的!那么,需要看一下是哪里引起的如此耗时。
这里还可以以图片的形式展示出来:
systemd-analyze --order plot > boot.svg
然后通过Chrome就可以看一下这个文件的全局了。
user@linux:~$ systemd-analyze --order
Startup finished in 3.515s (kernel) + 10min 4.683s (userspace) = 10min 8.198s
graphical.target reached after 10min 4.623s in userspace
user@linux:~$ systemd-analyze blame
10min 3.354s displaytouch.service
11.693s k3s.service
5.428s rc-local.service
3.185s dev-zram0.device
3.130s dev-zram1.device
3.123s docker.service
3.071s dev-zram2.device
3.039s dev-zram3.device
2.956s dev-zram5.device
2.953s dev-zram4.device
2.484s dev-nvme0n1p1.device
1.930s srs.service
1.353s apt-daily-upgrade.service
1.272s apt-daily.service
999ms udisks2.service
965ms nv-l4t-usb-device-mode.service
...
这样系统启动在哪里卡住一目了然。
还有一个是 systemd-analyze critical-chain xx
也是值得使用的一个命令。
sudo systemctl list-units --failed --all
还得最好根据type
来定:
systemctl list-units --type=target --all
systemd-analyze blame
可以知道当前系统启动的时间长短,但是如果提示:
bootup is not yet finished...
则可以使用
systemctl list-jobs
看哪些jobs在running和waiting.