Bash 스크립트에서 다음 명령을 실행하려고 합니다.
rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`
비슷한 것을 시도하고 있습니다.
RM_CMD="$(rm -rf 'ls -t ${FOLDER}/other_folder | awk NR>5')"
나중에 함수에서 사용하여 명령이 실제로 실행되기를 원합니다.
여러 변형을 시도했지만 항상 실패했습니다. 여기서 올바른 접근 방식은 무엇입니까?
-편집하다-
추가 정보
내가 다음과 같은 것을 시도하면
RM_CMD="rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`"
명령을 즉시 실행하려고 시도하는 것 같습니다. 이는 내 의도가 아니지만(나중에 실행하기 위해 올바른 명령을 저장하고 싶습니다) 올바른 값을 모두 얻습니다. 즉, 빈 값은 하나도 없습니다.
-편집 2-
나는 다음과 같이 명령을 최대한 많이 나누려고 노력합니다.
LS_CMD="ls -t ${FOLDER}/other_folder"
AWK_CMD="awk 'NR>5' ${LS_CMD}"
RM_CMD="rm -rf '${AWK_CMD}'"
하지만 이런 문제가 발생합니다.
+ ssh -t user@server 'rm -rf '\''awk '\''NR>5'\'' ls -t /full/path/to/folder/other_folder'\'''
bash: 5 ls -t /full/path/to/folder/other_folder: No such file or directory
답변1
일반적으로 이와 같은 질문에 대한 대답은 다음을 읽는 것입니다.BashFAQ #50: "명령을 변수에 넣으려고 하는데 복잡한 경우에는 항상 실패합니다!". 간략한 요약: 변수는 실행 가능한 코드가 아닌 데이터를 위한 것이므로 코드를 삽입하려고 하면 온갖 종류의 문제에 직면하게 됩니다.
하지만 이 경우에는 또 다른 핵심 요소가 있습니다. 를 통해 명령을 실행한다는 것입니다 ssh
. 즉, 명령이 원격 시스템으로 전달된다는 의미입니다.데이터로, 원격 시스템의 셸에 의해 명령으로 구문 분석됩니다. 이는 스크립트(로컬 시스템)의 변수에 명령(데이터)을 저장하는 것이 의미가 있음을 의미합니다.
당신이 가진 가장 큰 문제는 백틱을 사용하거나 $( )
작은 따옴표로 묶이지 않은 경우 내부 명령이 즉시 (로컬 시스템에서) 실행되고 해당 출력이 변수에 저장된다는 것입니다. 이를 방지하려면 변수를 정의할 때 관련 문자를 이스케이프 처리하면 됩니다.
RM_CMD="rm -rf \$(ls -t '${FOLDER}/other_folder' | awk 'NR>5')"
$( )
일반적으로 선호되기 때문에 백틱을 대신 사용하고 있습니다 . 제가 보기에는 역따옴표와 작은따옴표를 어느 시점에서 혼동한 것 같습니다. 둘은 비슷해 보이지만 완전히 다른 효과를 가지고 있습니다. $( )
본질적으로 동일한 작업을 수행하지만 시각적으로 모호하지는 않습니다.
${FOLDER}
또한 로컬 컴퓨터의 변수이므로 즉시 확장해야 한다고 가정합니다 (공백이나 다른 쉘 메타 문자가 포함된 경우에는 주위에 작은따옴표를 추가했습니다). 원격 쉘, 용도 변경 \"\${FOLDER|/other_folder\"
. 실제로 ${FOLDER}
작은따옴표 자체가 포함된 경우 작은따옴표를 둘러싸는 것은 작동하지 않습니다. 이 문제를 해결할 수 있는 방법이 있지만 여기서는 고민하지 않습니다.
변수 할당에 작은 따옴표를 사용할 수도 있지만 명령에서 작은 따옴표를 사용하는 데 문제가 발생할 수 있으며 (작은 따옴표로 묶인 문자열 내에 작은 따옴표를 중첩할 수 있는 확실한 방법은 없습니다) 로컬에서 awk
이를 수행할 수 있는 깔끔한 방법이 없습니다. ${FOLDER}
기계를 확장하세요. 이는 참조를 혼합하여 해결할 수 있지만 지저분합니다.
마지막으로 변수를 사용할 때는 큰따옴표로 묶어야 합니다.
ssh -t user@server "$RM_CMD"
...이 특별한 경우에는 문제가 되지 않지만 큰따옴표가 아닌 변수 참조에는 모든 종류의 문제가 있을 수 있으므로 일반적으로 큰따옴표를 사용하는 것이 좋습니다.