저는 bash를 처음 접했습니다. 간단한 명령을 사용하여 한 번에 하나의 간단한 관리 작업을 수행할 수 있습니다. 그러나 나는 텍스트 파일을 이름 바꾸기 소스로 사용하여 디렉토리의 일부 파일 이름을 바꾸는 임무를 맡고 있으며 내 능력을 훨씬 뛰어넘기 때문에 몇 가지 조언을 정말 감사하게 생각합니다.
설명하겠습니다.
New File Name.xlsx 0.1 000011F4.dat
New File Name.xlsx 0.2 000011F5.dat
New File Name.xlsx 0.3 000011F6.dat
New File Name.xlsx 0.4 000011F7.dat
New File Name.xlsx 0.5 000011F8.dat
New File Name.xlsx 0.6 000011F9.dat
내 소스 텍스트 파일은 위와 비슷합니다. 목적은 첫 번째 "열"이 파일의 새 이름이고, 중간이 버전이고, 세 번째 열이 현재 파일 이름이라는 것입니다.
디렉터리에 있는 .dat 파일의 이름을 첫 번째 열에 표시된 이름으로 변경해야 합니다. 또한 각 파일의 시작 부분에 버전 번호 0.1, 0.2 등을 추가해야 합니다.
몇 가지 질문이 있습니다.
파일에 공백이 있는 것이 큰 문제입니까? 각 파일 문자열 주위에 ""를 추가하는 것이 더 낫습니까?
기본적으로 어디서부터 시작해야할지 모르겠습니다. 도움을 주시면 대단히 감사하겠습니다. 보시다시피, 파일 이름 시작 부분에 버전 열을 추가하고 목록에 공백을 추가해야 하는 일반적인 이름 바꾸기보다 조금 더 복잡합니다.
답변1
이것은 작동합니다:
sh <(sed -r 's/^\s*(.*)\s+([0-9\.]+)\s+([0-9A-Z]{8}\.dat)\s*$/mv -iv \3 "\2 \1"/' files)
... files
소스 파일의 이름이 있는 곳입니다.
이것이 하는 일은 다음을 사용하여 명령 결과를 sed
(셸)의 새 인스턴스 로 전달하는 것입니다.sh
프로세스 교체. 이 명령의 출력은 다음 sed
과 같습니다.
mv -iv 000011F4.dat "0.1 New File Name.xlsx"
mv -iv 000011F5.dat "0.2 New File Name.xlsx"
mv -iv 000011F6.dat "0.3 New File Name.xlsx"
mv -iv 000011F7.dat "0.4 New File Name.xlsx"
mv -iv 000011F8.dat "0.5 New File Name.xlsx"
mv -iv 000011F9.dat "0.6 New File Name.xlsx"
이 sed
명령을 분석하여 패턴을 검색합니다.
^
- 줄의 시작\s*
- 처음에 공백이 있으면(.*)
- 모든 문자(결과는 괄호 안에 저장됨\1
)\s+
- 적어도 하나의 공백 문자([0-9\.]+)
0-9
- 및 중 하나 이상.
(에 저장\2
)\s+
- 적어도 하나의 공백 문자([0-9A-Z]{8}\.dat)
0-9
A-Z
- 안이나 그 뒤에 오는 8자.dat
(에 저장\3
)\s*
- 끝에 공백이 있으면$
- 줄 끝
...이를 로 바꿉니다 mv -iv \3 "\2 \1"
. 여기서 \1
to \3
는 이전에 저장된 값입니다. 원하는 경우 버전 번호와 파일 이름의 나머지 부분 사이에 공백 이외의 다른 것을 사용할 수 있습니다.
결과는 다음과 같습니다.
$ ls -l
total 60
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F4.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F5.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F6.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F7.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F8.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F9.dat
-rw-rw-r-- 1 z z 222 Aug 8 13:47 files
$ sh <(sed -r 's/^\s*(.*)\s+([0-9\.]+)\s+([0-9A-Z]{8}\.dat)\s*$/mv -iv \3 "\2 \1"/' files)
`000011F4.dat' -> `0.1 New File Name.xlsx'
`000011F5.dat' -> `0.2 New File Name.xlsx'
`000011F6.dat' -> `0.3 New File Name.xlsx'
`000011F7.dat' -> `0.4 New File Name.xlsx'
`000011F8.dat' -> `0.5 New File Name.xlsx'
`000011F9.dat' -> `0.6 New File Name.xlsx'
$ ls -l
total 60
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.1 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.2 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.3 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.4 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.5 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.6 New File Name.xlsx
-rw-rw-r-- 1 z z 222 Aug 8 13:47 files
답변2
sed 's/^\(.*\.xlsx\) \+\([[:digit:]]\+\.[[:digit:]]\+\) \+\(.[^ ]*\)/"\3" "\2\1"/' \
<file_list | xargs -n 2 mv
이렇게 하면 행이 이전 부분으로 분할됩니다 .xlsx
. 이는 새 이름의 두 번째 부분이며 를 통해 액세스할 수 있습니다 \1
. 버전을 가져와서 \2
후행 공백을 무시하고 이전 파일 이름을 .
이는 참조되어 mv
매개변수로 제공됩니다. 이전 파일 이름과 새 파일 이름이라는 두 가지 매개변수를 -n 2
받아야 합니다 .mv
이러한 공백은 아무런 문제를 일으키지 않습니다. 문제를 복잡하게 만드는 것은 입력 목록의 구조가 잘못되어 있다는 것입니다. 열과 참조 파일 이름을 바꾸려면 미리 수행하지 않고 xargs
and 를 사용하면 됩니다 mv
.
답변3
파일 이름에 공백이 있고 일부 열 사이에 여러 공백을 사용하면 이 작업이 더 어려워지지만 결코 극복할 수 없는 것은 아닙니다.
목록 파일을 한 줄씩 읽습니다. 보통 사람들이 사용하게 될while IFS= read -r; do …
하지만 여기에서는 선행 및 후행 공백을 제거하는 것이 더 강력할 수 있습니다. 각 행에 대해 다음을 수행합니다.
- 각 행을 세 부분으로 나눕니다. 한 가지 방법은 정규식 일치를 사용하는 것입니다.
[[:space:]]+
하나 이상의 공백 문자(공백 또는 탭)와 일치합니다.[[:space:]]+
하나 이상의 공백이 아닌 문자와 일치합니다.BASH_REMATCH
괄호 안의 그룹은 변수를 통해 검색할 수 있습니다 .
여기서 덜 편리한 또 다른 방법은 변수에서 각각 접두사 또는 접미사를 사용${VAR##PATTERN}
하거나 제거하는 것입니다.${VAR%PATTERN}
- 마지막으로 작업을 수행합니다. 오류를 기록하는 것을 잊지 마세요.
함께 넣어보세요:
ret=0
while read line; do
if [[ $line =~ (.*[^[:space:]])[[:space:]]+([^[:space:]]+)[[:space:]]+([^[:space:]]+) ]]; then
new_name="${BASH_REMATCH[1]}"
version="${BASH_REMATCH[2]}"
old_name="${BASH_REMATCH[3]}"
mv -- "$old_name" "$version$new_name" || ret=1
else
echo "Malformed line: $line"
fi
done <name_list.txt
exit $ret
답변4
해결 방법은 awk
다음 명령을 실행하는 것입니다.
awk '{print "/bin/mv", $NF, "\"" $(NF-1), gensub(/^([^.]+\.xlsx).*/, "\\1", 1) "\"" | "bash" } ; END { close("bash") }' sourcefile
이전 명령은 bash
명령 출력을 셸로 파이프합니다.
awk '{print "/bin/mv", $NF, "\"" $(NF-1), gensub(/^([^.]+\.xlsx).*/, "\\1", 1) "\""}' sourcefile
먼저 실행하여 실제로 원하는 작업인지 확인해야 합니다! 이 awk
명령은 소스 파일의 각 줄을 인쇄하고 /bin/mv
, 줄의 마지막 공백으로 구분된 필드, 큰따옴표, 줄의 마지막에서 두 번째 필드를 차례로 인쇄한 다음 전체 줄을 Everything 으로 바꿉니다 .xlsx
. 그 뒤에 큰따옴표로 묶인 결과가 나옵니다.
다음은 귀하가 선호할 수 있는 변형입니다.
awk '{print "/bin/mv", $NF, "\"" "0." FNR, gensub(/^([^.]+\.xlsx).*/, "\\1", 1) "\"" | "bash" } ; END { close("bash") }' sourcefile
변수 FNR
는 행 번호입니다(따라서 소스 파일에서 항목 0.1, 0.2, 0.3, ...을 생략할 수 있음).
파일 이름의 공백은 "큰 문제"라고 부르지는 않지만 권장하지 않습니다. 새 파일 이름의 공백을 밑줄로 변경하는 최종 버전과 같은 것을 사용할 수 있습니다.
awk '{print "/bin/mv", $NF, "0." FNR "_" gensub(" ","_", "g", gensub(/^([^.]+\.xlsx).*/, "\\1", 1)) | "bash" } ; END { close("bash") }' sourcefile