awk
각 상위/중간 레벨의 첫 번째 문자를 사용하여 Unix 경로의 문자열을 단축하지만 전체 기본 이름을 사용하는 우아한 한 줄짜리 코드(예: )를 찾고 있습니다 . 예를 들어 설명하는 것이 더 쉽습니다.
/path/to/file
→/p/t/file
/tmp
→/tmp
/foo/bar/.config/wizard_magic
→/f/b/./wizard_magic
/foo/bar/.config/wizard_magic
→/f/b/.c/wizard_magic
아래 @MichaelKjörling 및 @ChrisH의 좋은 점을 고려하여 이 예에서는 첫 번째 문자가 점일 때 처음 두 문자를 표시하는 방법을 보여줍니다.
답변1
sed에서는 매우 간단합니다(파일 이름에 줄 바꿈이 없다고 가정).
sed 's!\([^/]\)[^/]*/!\1/!g'
awk에서는 역참조가 없기 때문에 쉽지 않습니다(Gawk는 제외하지만 구문이 어색합니다).
awk -v FS=/ -v OFS=/ '{for (i=1; i<NF; i++) $i=substr($i,1,1)} 1'
zsh에서(경로는 $full_path
):
echo "${(j:/:)${(@r:1:)${(@s:/:)${full_path:h}}}}/${full_path:t}"
답변2
다음을 수행할 수 있습니다.
cd /usr///.//share/../share//man/man1 || exit
IFS=/; set -f
printf %.1s/ ${PWD%/*}
printf %s\\n "${PWD##*/}"
/u/s/m/man1
이것은 sed
:
printf %s "$file" |
tr /\\n \\n/ | sed -et$ \
-e '\|^\.\.$|{x;s|\(.*\)\n.*$|\1|;x;}' \
-e 's|^\.\{0,2\}$||;\|.|H;$!d;x' \
-e$ -e '\|\(\.\{0,2\}.\)\(.*\)\(\n\)|!b' \
-e 's||\1\3\2\3|;P;s|\n||;D' |
tr /\\n \\n/
이는 아래 함수가 수행하는 모든 작업과 매우 유사합니다. 함수처럼 물결표로 축약되지 않거나 $PWD
슬래시가 아닌 선행 문자로 헤더에 삽입됩니다.(실제로 선행 슬래시는 인쇄되지 않습니다.)하지만 이 문제는 나중에 다룰 수 있습니다. 빈 경로 구성 요소와 단일 지점을 처리하고 ..
사례를 지웁니다.
man
위와 동일한 경로가 주어지면 cd
다음이 인쇄됩니다.
u/s/m/man1
또한 1~2개가 아닌 이것으로 시작하는 각 경로 구성 요소에 대해 1~2개의 추가 선행 지점을 인쇄합니다.
로 시작하는 경로 구성 요소에 대해 여러 문자를 사용할 것인지 묻습니다 .
. 그러기 위해서는 각 구성 요소에 개별적인 주의가 필요하다고 판단했고, 궁금했기 때문에 디렉터리를 변경하지 않고 표준 경로를 알아내려고 노력했습니다. 몇 번의 시행착오 끝에 마침내 이 작업을 올바르게 수행하는 유일한 방법은 이 작업을 앞뒤로 두 번 수행하는 것이라고 결정했습니다.
pathbytes(){
local IFS=/ o="$-" p
set -f${ZSH_VERSION+LFy}
set -- ${1:-$PWD}
for p in /${1:+$PWD} $*
do case $p in (.|"") ;;
(..) ${1+shift} ;;
(/) set -- ;;
(*) set -- $p $*; esac
done
for p in //$* ""
do case ${p:-/$3} in
([!./]*) ;;
(..*) set "..$@" ;;
(.*) set ".$@" ;;
(//*) ! set "" $1 $1 ;;
(~) ! p=\~ ;;
(~/*) p="~/$2";set $HOME
! while "${2+shift}" 2>&3
do p="~/${p#??*/}"
done 3>/dev/null;;
esac&& set "" "${p%"${p#$1?}"}/$2" "$p/$3"
done; printf %s\\n "${p:-$2}"
set +f "-${o:--}"
}
이는 디렉터리를 변경하거나 경로 구성 요소가 있는지 확인하려고 시도하지 않지만 중복 /
구분 기호를 압축하고 /./
단일 점 구성 요소를 완전히 제거하며 /../
이중 점 구성 요소를 적절하게 처리합니다.
$IFS
일부로 설정 하면공백이 아닌문자가 있는 경우 두 개 이상의 문자 시퀀스 $IFS
로 인해 하나 이상의 빈 필드가 생성됩니다. 따라서 여러 개의 연속 슬래시가 null 매개변수를 계산할 수 있습니다. 주인공도 마찬가지다 $IFS
. 따라서 set -- $1
분할할 때 결과가 $1
비어 있으면 슬래시로 시작하고, ${1:+$PWD}
비어 있지 않으면 를 삽입합니다 $PWD
. 즉, 첫 번째 인수가 슬래시로 시작하지 않으면 $PWD
Front에 추가됩니다. 이 길이 가장 가깝습니다확인하다.
그렇지 않으면 첫 번째 for
루프는 경로 구성 요소의 순서를 재귀적으로 반대로 바꿉니다. 예를 들면 다음과 같습니다.
1 2 3
1 2 3
2 1 3
3 2 1
...이 작업을 수행할 때 단일 점이나 빈 구성 요소는 무시됩니다 ..
.
1 .. 3
1 .. 3
3
3
...두 번째 패스는 이 효과를 반전시키고 그렇게 함으로써 각 구성요소를 둘 중 하나로 압착합니다.2포인트 + 문자, 또는1포인트 + 문자, 또는성격.
따라서 존재 여부에 관계없이 표준 경로를 따라야 합니다.
두 번째 루프에서 비트를 더하거나 뺍니다. 이제 set
점점 줄어들어요(각 구성요소는 한 번만 사용할 수 있습니다 [!./]*
.)case
, 그리고 대부분의 경우 단락 모드가 평가합니다.(위 패턴 덕분에)에 대한 최종 호출 일치 평가를 포함합니다 ~
. 전부 또는 주요 부분인 경우(전체 구성요소로 나누어짐)최종 정식 경로는 일치할 수 있으며 ~
, 일치하는 비트는 제거되어 ~
리터럴로 대체됩니다. 이를 위해 경로와 약어의 전체 사본도 보관해야 했습니다.(축약된 경로를 일치시키는 것은 ~
그다지 도움이 되지 않을 수 있으므로)이므로 이는 에 유지됩니다 $3
. 마지막 루프 분기는 의 하위 집합과 일치할 때만 실행됩니다 while
.~
$3
추적이 활성화된 상태에서 실행하면 set -x
작동하는 것을 볼 수 있습니다.
$ (set -x;pathbytes ..abc/def/123///././//.././../.xzy/mno)
+ pathbytes ..abc/def/123///././//.././../.xzy/mno
+ local IFS=/ o=xsmi p
+ set -f
+ set -- ..abc def 123 . . .. . .. .xzy mno
+ set --
+ set -- home
+ set -- mikeserv home
+ set -- ..abc mikeserv home
+ set -- def ..abc mikeserv home
+ set -- 123 def ..abc mikeserv home
+ shift
+ shift
+ set -- .xzy ..abc mikeserv home
+ set -- mno .xzy ..abc mikeserv home
+ set mno mno
+ set . mno mno
+ set .x/mno .xzy/mno
+ set .. .x/mno .xzy/mno
+ set ..a/.x/mno ..abc/.xzy/mno
+ set m/..a/.x/mno mikeserv/..abc/.xzy/mno
+ set h/m/..a/.x/mno home/mikeserv/..abc/.xzy/mno
+ p=~/h/m/..a/.x/mno
+ set home mikeserv
+ shift
+ p=~/m/..a/.x/mno
+ shift
+ p=~/..a/.x/mno
+
+ printf %s\n ~/..a/.x/mno
~/..a/.x/mno
+ set +f -xsmi
답변3
이 테스트 파일의 경우:
$ cat path
/path/to/file
/tmp
/foo/bar/.config/wizard_magic
다음 awk 코드를 사용하여 약어를 생성할 수 있습니다.
$ awk -F/ '{for (i=1;i<NF;i++) $i=substr($i,1,1)} 1' OFS=/ path
/p/t/file
/tmp
/f/b/./wizard_magic
Edit1: 두 문자를 점호로 사용
이 버전은 디렉터리 이름을 한 문자로 축약하지만 이름은 .
두 문자로 시작합니다.
$ awk -F/ '{for (i=1;i<NF;i++) $i=substr($i,1,1+($i~/^[.]/))} 1' OFS=/ path
/p/t/file
/tmp
/f/b/.c/wizard_magic
어떻게 작동하나요?
-F/
이는 awk에게 슬래시를 입력 필드 구분 기호로 사용하도록 지시합니다.
for (i=1;i<NF;i++) $i=substr($i,1,1)
그러면 각 필드(마지막 필드 제외)를 반복하고 첫 번째 문자로만 바꿉니다.
EDIT1: 수정된 버전에서는 필드가 로 시작할 때 하위 문자열의 길이를 2로 설정했습니다
.
.1
이는 수정된 행을 인쇄하도록 awk에 지시합니다.
OFS=/
이는 awk에게 출력에서 슬래시를 필드 구분 기호로 사용하도록 지시합니다.
답변4
짧은 이름을 사용하시겠습니까, 아니면 명령줄에서 사용하시겠습니까?
명령줄에 대해 다음 제안 사항이 있습니다.
셸에서 파일 완성이 도움이 되지 않습니까?
운이 좋아서 특별한 일을 할 필요가 없는 경우도 있습니다.
# /path/to/file -> /p/t/file
ls -l /*/*/file
# /tmp -> /tmp
cd /tmp
# /foo/bar/.config/wizard_magic -> /f/b/./wizard_magic
ls -l /*/*/*/wizard_magic -> /f/b/./wizard_magic
관심 있는 디렉터리가 몇 개만 있는 경우 별칭을 사용할 수 있습니다.
alias cdto="cd /path/to"
alias cdtmp="cd /tmp"
alias cdcfg="cd /foo/bar/.config"
alias cddeep="cd /home/john/workdir/project1/version3/maven/x/y/z/and/more"
또는 즐겨찾는 디렉터리에 대한 변수를 설정할 수 있습니다.
export p="/path/to"
export f="/foo/bar/.config"
ls -l $p/file
ls -l $f/wizard_magic
나는 이러한 옵션이 .bashrc(또는 .profile)에 정의된 함수를 사용하여 이 문제를 해결하려고 시도하는 것보다 더 의미가 있다고 생각합니다.
function x {
xxpath=""
while [ $# -ne 0 ]; do
xxpath+="${1}*/"
shift
done
cd $(echo "${xxpath}")
}
문자 사이에 공백을 넣어 이 함수 x를 호출합니다.
# cd /path/to
x /p t
# cd /tmp
x /t
# cd /foo/bar/.config
x /f b