使用 awk 將文件的符號連結列表發送到名稱中包含空格的目錄?
我有一個要創建軟連結的文件名列表(呼叫它
filenames.txt
)。使用時cat filenames.txt | awk 'system("ln -s "$0" ~/directory\ with\ spaces/subdirectory/")`
當遇到任何帶有空格的東西(文件名或目標目錄)時,它似乎會窒息。
如何創建這些軟連結而不必先重命名所有內容以確保沒有空格?
注意:此處提供的所有範例都將從文件和文件名列表所在的目錄執行。例如,如果它們在
/mnt/Hard\ Drive/some\ files/
文件夾中,請確保它們filenames.txt
也儲存在那裡。從 shell 執行命令時,請cd /mnt/Hard\ Drive/some\ files/
然後執行範例。AWK
AWK 的系統呼叫可以用於包含空格的項目,但它稍微複雜一些。您的原始程式碼有一些語法錯誤並且
cat
在那裡毫無用處。不管這個事實如何,正確的方法是先將命令建構sprintf()
到變數中,然後將該變數傳遞給system()
. 像這樣:$ ls dir\ with\ spaces/ $ awk '{cmd=sprintf("fpath=$(realpath -e \"%s\" );%s %s \"$fpath\" \"%s\"",$0,"ln","-s","dir with spaces/");system(cmd) }' filenames.txt $ ls dir\ with\ spaces/ ascii.txt@ disksinfo.txt@ input.txt@ process info.txt@
BASH(或任何類似 Bourne 的 shell)
阻力較小的路徑將通過下面給出的小 shell 腳本:
#!/bin/bash # uncomment set -x for debugging #set -x # Preferably, the directory should be full path dir="dir with spaces/" while IFS= read -r line do if [ "x$line" != "x" ] && [ -e "$line" ]; then fpath=$( realpath -e "$line" ) ln -s "$fpath" "$dir" fi done < filenames.txt
執行中的腳本:
$ ls -l dir\ with\ spaces/ total 0 $ cat filenames.txt input.txt ascii.txt disksinfo.txt process info.txt $ ./makelinks.sh $ ls -l dir\ with\ spaces/ total 0 lrwxrwxrwx 1 xieerqi xieerqi 9 1月 15 00:47 ascii.txt -> ascii.txt lrwxrwxrwx 1 xieerqi xieerqi 13 1月 15 00:47 disksinfo.txt -> disksinfo.txt lrwxrwxrwx 1 xieerqi xieerqi 9 1月 15 00:47 input.txt -> input.txt lrwxrwxrwx 1 xieerqi xieerqi 16 1月 15 00:47 process info.txt -> process info.txt
它的工作方式很簡單:
while IFS= read -r line; do . . . done < filenames.txt
逐行讀取 filenames.txt,每個時間行都進入line
變數。我們檢查該行是否不為空以及文件是否存在(此腳本將從原始文件和文件列表所在的同一目錄執行)。如果兩個條件都為真,我們就建立連結。請注意,您應該確保文件以換行符結尾 - 如果最後一行不以換行符結尾(確實發生),則將跳過最後一行,因此不會為該文件建立任何連結.
儘管不理想且並非沒有怪癖,但對於 awk
system()
不可用的情況(這在當今可能很少見),這是一個可行的解決方案。xargs
一個稍微簡單的 shell 方法是通過
xargs
andbash -c '' sh
,我們再次讀取 filenames.txt ,使用標誌逐行讀取-L1
,並將每一行用作 bash 的參數。使用$@
我們獲取整個命令行參數數組( $ 1, $ 2,3美元。. . 等)並變成字元串變數,然後將其傳遞給ln
. 最後sh
是設置$0
變數。是否有必要這樣做是有爭議的,但這不是這個問題的主題,因此讓我們跳過它:)$ xargs -I {} -L1 bash -c 'file="$@";fpath=$(realpath -e "$file"); ln -s "$fpath" ./dir\ with\ spaces/"$file" ' sh < filenames.txt $ ls dir\ with\ spaces/ ascii.txt@ disksinfo.txt@ input.txt@ process info.txt@
Python
$ ls dir\ with\ spaces/ $ python -c "import os,sys;fl=[f.strip() for f in sys.stdin];map(lambda x: os.symlink(os.path.realpath(x),'./dir with spaces/' + x),fl)" < filenames.txt $ ls dir\ with\ spaces/ ascii.txt@ disksinfo.txt@ input.txt@ process info.txt@
它的工作方式很簡單——我們重定向
filenames.txt
到 pythonstdin
中,將每一行讀入 listfl
,然後為 listos.symlink()
中的每個項目執行。冗長的單線,但有效。Perl
更短的版本是通過 Perl 實現的:
$ perl -lane 'use Cwd "realpath";symlink(realpath($_),"./dir with spaces/" . $_)' < filenames.txt $ ls dir\ with\ spaces/ ascii.txt@ disksinfo.txt@ input.txt@ process info.txt@