중복 명령이 있는지 $PATH를 확인하는 방법은 무엇입니까?

중복 명령이 있는지 $PATH를 확인하는 방법은 무엇입니까?

예를 들어 youtube-dl을 컴퓨터에 설치하는 방법은 다양합니다. 실수로 여러 가지 방법으로 여러 번 다운로드/설치했기 때문에 $PATH 디렉토리, , 및 /usr/local/bin/youtube-dl에 여러 개의 youtube-dl 실행 파일이 생성되었습니다 . 따라서 업그레이드된 버전 "2021.01.03"을 설치했는데도 $PATH의 다른 디렉터리에 있는 youtube-dl이 어떻게든 덮어썼기 때문에 "2020.07.28"로 표시됩니다./home/username/.local/bin/youtube-dl/usr/local/bin/youtube-dlyoutube-dl --version

그래서 여기서는 $PATH에서 동일한 이름을 가진 모든 설치된 파일을 확인하여 해당 버전을 즉시 확인하고 어떤 것이 최신인지, 최신인지, 어떤 것을 제거해야 하는지 확인하고 싶습니다. 그렇다면 이를 수행할 수 있는 방법이나 CLI 도구가 있습니까? 감사해요.

답변1

대화형으로는 다음을 사용합니다.

ls -l $(type -ap youtube-dl)

youtube-dl내 $PATH에서 모든 프로그램의 위치와 타임스탬프를 찾습니다 .

물론 이름에 공백이 있는 실행 파일에서는 작동하지 않지만 youtube-dl그 중 하나는 아닙니다.

답변2

PATH 디렉터리에 순차적으로 액세스하고 실행할 파일 위치를 나열하려면 다음 which명령을 사용할 수 있습니다.

$ which -a command_name

답변3

다음 스크립트는 변수에 의해 나열된 디렉터리에 있는 중복 실행 파일 목록을 출력합니다 $PATH.

탭으로 구분된 2열 실행 파일 목록을 생성하여 이를 수행합니다. 여기서 첫 번째 열은 디렉터리 경로 이름이고 두 번째 열은 실행 파일의 파일 이름입니다.

awk이 목록은 각 실행 파일이 발견된 횟수를 세고 탭으로 구분된 문자열에서 각 실행 파일에 대한 모든 디렉터리 경로 이름을 수집하는 간단한 프로그램으로 읽혀집니다 .

마지막으로 awk코드는 정확한 이름이 여러 번 발견된 각 실행 파일과 해당 파일이 발견된 디렉터리 경로 이름의 탭으로 구분된 목록을 출력합니다. 검색된 순서대로 디렉터리가 나열되며, 다음 디렉터리에서 실행 파일이 선택됩니다.첫 번째명령줄에서 명시적인 경로 없이 사용하면 디렉터리(현재 값이 지정됨 $PATH)가 나열됩니다.

#!/bin/sh

# turn off filename globbing, and
# split strings in unquoted variables on colons
set -f; IFS=:

# set the positional parameters to the list of
# directories in the PATH variable
set -- $PATH

# turn on filename globbing again
# (leave IFS as is, it won't affect anything else here)
set +f

# loop over those directories and do the things
for dir do
        for pathname in "$dir"/*; do
                [ -x "$pathname" ] && printf '%s\t%s\n' "$dir" "${pathname##*/}"
        done
done |
awk -F '\t' '
{
        dir[$2] = ( dir[$2] == "" ? $1 : dir[$2] "\t" $1 )
        count[$2]++
}
END {
        for (util in dir)
                if (count[util] > 1)
                        printf "%s\t%s\n", util, dir[util]
}'

내 OpenBSD 시스템에서 실행되는 예입니다. 출력을 전달하여 column -t형식을 적절하게 지정한 다음 정렬합니다.

$ sh script | column -t | sort
banner       /usr/bin                /usr/games
bash         /home/myself/local/bin  /usr/local/bin
bashbug      /home/myself/local/bin  /usr/local/bin
chgrp        /bin                    /usr/sbin
chown        /usr/sbin               /sbin
clang        /usr/bin                /usr/local/bin
clang++      /usr/bin                /usr/local/bin
clang-cpp    /usr/bin                /usr/local/bin
ld.lld       /usr/bin                /usr/local/bin
llvm-config  /usr/bin                /usr/local/bin
python3      /home/myself/local/bin  /usr/local/bin
python3.8    /home/myself/local/bin  /usr/local/bin
sysctl       /usr/sbin               /sbin
zsh          /home/myself/local/bin  /usr/local/bin

명령줄에서 실행 하면 명령줄 에서 bash실행 /home/myself/local/bin되고 .bash/usr/local/bin

답변4

동일한 이름을 가진 설치된 파일을 모두 확인하고 싶습니다.$PATH

여기에 또 다른 제안이 있습니다. findacross를 사용하여 $PATH파일 이름을 얻고 awk중복 항목과 일치시키는 것입니다. 원한다면 한 줄로 묶을 수도 있지만 가독성을 위해 여러 줄에 걸쳐서 표시했습니다.

( IFS=:; find $PATH -maxdepth 1 -type f ) |    # See below for alternative without maxdepth
    awk -F/ '
        {
            p[$NF] = p[$NF] "\n" $0;           # Save the pathname ($NF is last component)
            h[$NF] ++                          # Count this instance of the filename
        }
        END {
            for (f in h) {
                if (h[f] >1) { print p[f] }    # Print list iff we have multiple hits
            }
        }
    '

find아무런 조치가 없으면 첫 -maxdepth번째 줄을 다음으로 바꿀 수 있습니다.이 확장

( IFS=:; for dir in $PATH; do find dir ! -path dir -prune -type f; done ) |

읽을 수 없지만 한 줄로 묶인 버전

(IFS=:; find $PATH -maxdepth 1 -type f)|awk -F/ '{p[$NF]=p[$NF]"\n"$0;h[$NF]++}END{for(f in h){if(h[f]>1){print p[f]}}}'

관련 정보