خط فرمان لینوکس

ترجمه فارسی LinuxCommand.org

خط فرمان لینوکس

ترجمه فارسی LinuxCommand.org

program_list

program_list

آیا هیچ از آن همه فایلهای داخل ‎/usr/bin‎ تعجب کرده‌اید؟ البته که تعجب کرده‌اید! بسیار خوب، شما می‌توانستید یک whatis روی هر فایل در دایرکتوری(که در یک سیستم معمولی تعداد آنها می‌تواند یکهزار یا بیشتر باشد) انجام بدهید، یا می‌توانید اسکریپت زیر را اجرا کنید.

program_list برنامه‌ای است که یک لیست تفسیری از برنامه‌های یک دایرکتوری(پیش‌فرض آن ‎/usr/bin‎ است) با نمایش شرح هر برنامه تولید می‌کند. همچنین، نام بسته‌ای را که برنامه به آن تعلق دارد نیز لیست می‌کند، یک سرنخِ مفید دیگر برای تعیین آنچه برنامه انجام می‌دهد.

برنامه خروجی‌اش را در سه قالب متفاوت به خروجی استاندارد ارسال می‌کند، متن ساده(پیش‌فرض)، کمیت‌های جدا‌شده با tab (عالی برای پردازش بعدی لیست با سایر ابزارها یا بارگذاری آن داخل یک صفحه‌گسترده)، و قالب Markdown برای تبدیل مستقیم به HTML و سایر قالب‌ها.

program_list باید در هر سیستم بر مبنای rpm (از قبیل Red Hat‏، CentOS‏، Fedora، وغیره) یا بر پایه deb (مانند Debian‏، Ubuntu‏، و غیره) کار کند. به هر حال توجه داشته باشید که به سبب سرعت پایین جستجوی بسته روی اکثر سیستم‌ها، اجرای program_list می‌تواند زمان زیادی(تا نیم ساعت یا بیشتر) نسبت به سرعت سیستم شما و تعداد فایل‌های موجود، صرف کند.

علاوه بر دایرکتوری پیش‌فرض ‎/usr/bin‎، برای دایرکتوری ‎/bin‎‏، ‎/sbin‎، و ‎/usr/sbin‎ نیز مناسب است.

مثال‌ها

me@linuxbox ~ $ program_list > program_list.txt

یک لیست متن ساده از ‎/usr/bin‎ تولید می‌کند و آن را در فایلی به نام program_list.txt ذخیره می‌کند.

me@linuxbox ~ $ program_list -t /usr/sbin > program_list_usr_sbin.tsv

یک لیست با کمیت‌ جدا شده با tab از ‎/usr/sbin‎ تولید و آن را در فایلی به نام program_list_usr_sbin.tsv ذخیره می‌کند.

#!/bin/bash
# ---------------------------------------------------------------------------
# program_list - تولید یک لیست تفسیری از برنامه‌ها

# Copyright 2014, William Shotts <bshotts@users.sourceforge.net>
  
#  این برنامه نرم‌افزار آزاد است: شما می‌توانید آن را تحت شرایط نگارش  
#    گنو یا به انتخاب خودتان هر نگارش پس از آن که GPL‎  شماره 3 مجوز 
#  .توسط بنیاد نرم‌افزارهای آزاد اعلام گردیده، ‏توزیع و یا ویرایش کنید‎

# این برنامه به امید آنکه سودمند باشد توزیع می‌گردد، اما بدون هرگونه‎
#  تعهد حتی تعهد ضمنی کیفیت یا صلاحیت برای یک مقصود خاص. برای جزییات 
#  .ببینید ‎(http://www.gnu.org/licenses/)‎  گنو را در GPL بیشتر مجوز‎

# ‎/usr/bin‎ این برنامه یک لیست تفسیری از برنامه‌های دایرکتوری
#  (یا دایرکتوری تعیین شده کاربر) شامل نام فایل، نام بسته‌ای
#  man که بواسطه آن نصب شده است و شرح مختصر اخذ شده از صفحه
#  برنامه اگر در دسترس باشد، تولید می‌کند. قالب لیست می‌تواند
#  (مفید برای tab متن ساده(قالب پیش‌فرض)، کمیت‌های جدا شده با
#  .باشد Markdown وارد کردن لیست به سایر برنامه‌ها)، یا قالب

#  program_list [-h|--help]		      : نحوه کاربرد
#  program_list [[-m|--markdown]|[-t|--tabs]] [directory]

#  :تاریخچه بازبینی
# 2014-01-27    در برابر نام‌های نا‌خوشایند تقویت گردید  ‏(ver. 1.1)‏
# 2014-01-17  ایجاد گردید new_script اسکریپت ‎3.0.1‎ به وسیله نگارش
# ---------------------------------------------------------------------------

PROGNAME=${0##*/}
VERSION="1.1"

clean_up() { # انجام خانه‌تکانی قبل از خروج
  return
}

error_exit() { # مدیریت خطاهای مهلک
  echo -e "${PROGNAME}: ${1:-"Unknown Error"}" >&2
  clean_up
  exit 1
}

graceful_exit() {
  clean_up
  exit
}

signal_exit() { # شده trap اداره سیگنال‌های 
  case $1 in
    INT)
      error_exit "Program interrupted by user" ;;
    TERM)
      echo -e "\n$PROGNAME: Program terminated" >&2
      graceful_exit ;;
    *)
      error_exit "$PROGNAME: Terminating on unknown signal" ;;
  esac
}

usage() {
  echo -e "Usage: $PROGNAME [-h|--help]|[[-m|-t] [directory]]"
}

help_message() {
  cat <<- _EOF_
  $PROGNAME ver. $VERSION
  Produce an annotated listing of programs in a directory

  $(usage)

  Options:
  -h, --help      Display this help message and exit.
  -m, --markdown  Output Markdown formatted text (with pandoc
                  extensions).
  -t, --tabs      Output tab-separated values.
  
  directory is optional. Default is /usr/bin.

_EOF_
  return
}

set_mode() { # تنظیم قالب خروجی
  if [[ $mode == "empty" ]]; then
    mode=$1
  else
    error_exit "Only one mode (-m or -t) is allowed."
  fi
}

string() { # مرتبه تکرار شده "width" که "char" نوشتن یک رشته کاراکتر

  local -i width="$1"
  local char="$2"

  head -c "$width" < /dev/zero | tr '\0' "$char"
}

find_package() { # جستجو برای نام بسته بر مبنای توزیع

  local filename="$1" raw_package

  case $distro_style in
    debian)
      raw_package="$(dpkg-query -S "$filename" 2> /dev/null | tail -1)"
      echo "${raw_package%:*}"
      ;;
    redhat)
      rpm -qf "$filename" 2> /dev/null
      ;;
    *)
      error_exit "Unsupported distribution."
      ;;
  esac
}

# Trap سیگنال‌های
trap "signal_exit TERM" TERM HUP
trap "signal_exit INT"  INT

# تجزیه سطر‌فرمان
mode=empty
program_directory=/usr/bin
while [[ -n "$1" ]]; do
  case "$1" in
    -h | --help)
      help_message
      graceful_exit
      ;;
    -m | --markdown)
      set_mode markdown
      ;;
    -t | --tabs)
      set_mode tsv
      ;;
    -* | --*)
      usage
      error_exit "Unknown option $1"
      ;;
    *)
      program_directory="$1"
      break
      ;;
  esac
  shift
done

# منطق اصلی

declare -a filenames packages descriptions
declare -i index=1 max_fn_len=0 fn_len=0 col1_width col2_width
distro_style="unknown"

# تعیین نوع سیستم بسته‌بندی
[[ -x /usr/bin/apt-get ]] && distro_style="debian"
[[ -x /bin/rpm || -x /usr/bin/rpm ]] && distro_style="redhat"

# معتبر است program_directory بررسی آن‌که
[[ -d "$program_directory" ]] || \
  error_exit "$program_directory cannot be read"
  
# بار گیری آرایه با نام فایل‌ها، بسته‌ها، و توضیح‌ها
while IFS= read -r i; do
  filenames[index]="${i##*/}"
  fn_len=${#filenames[index]}
  # تعیین طولانی‌ترین نام‌فایل برای محاسبه عرض ستون
  [[ $fn_len -gt $max_fn_len ]] && max_fn_len=$fn_len

  packages[index]="$(find_package "$i")"

  # گرفتن توضیح برنامه، دور ریختن ابتدای آن و 
  #          .بزرگ کردن حرف ابتدای اولین کلمه
  raw_description="$(whatis "${filenames[index]}" 2>/dev/null | head -1)"
  raw_description="${raw_description##*' - '}"
  descriptions[index]="${raw_description^*}"

  ((++index))
done < <(find "$program_directory" -mindepth 1 -maxdepth 1 -executable \
          -not -type d | sort -u)

#  Markdown درج سرآیند
if [[ $mode == "markdown" ]]; then
  markdown_header="Programs in $program_directory"
  echo -e "$markdown_header\n$(string ${#markdown_header} "=")\n\n"
  ((max_fn_len += 4)) # اجازه برای افزودن کاراکترهای اضافی به نام فایل‌ها
fi

# محاسبه عرض ستون‌ها
col1_width=$((max_fn_len + 1))
col2_width=$((80 - col1_width))

# Markdown درج جدول
if [[ $mode == "markdown" ]]; then
  echo "$(string $max_fn_len '-') $(string $col2_width '-')"
fi

for ((i=1; i<index; ++i)); do
  case $mode in
    empty)
      printf "%-${max_fn_len}s Package:%s\n" \
        "${filenames[i]}" \
        "${packages[i]}"
      # اندازه کردن توضیح برای ستون دوم
      echo "${descriptions[i]}" | \
        fold -s -w $col2_width | \
        pr -T -o $col1_width
      echo
      ;;
    tsv)
      printf "%s\t%s\t%s\n" \
        "${filenames[i]}" \
        "${packages[i]}" \
        "${descriptions[i]}" 
      ;;
    markdown)
      printf "%-${max_fn_len}s Package:%s\n\n" \
        "**${filenames[i]}**" \
        "${packages[i]}"
      echo "${descriptions[i]}" | \
        fold -s -w $col2_width | \
        pr -T -o $col1_width
      echo
      ;;
  esac
done

# Markdown بستن جدول
[[ $mode == "markdown" ]] && echo -e "$(string 80 '-')\n"

graceful_exit