Is it possible to edit a symlink with a text editor? - linux

When we create a symlink, the number of bytes the symlink takes up is exactly the length of the origin it points to. For instance,
$ ln -s dest link1
$ ln -s longer_dest link2
$ ls -l
lrwxrwxrwx 1 username 4 Mar 26 20:21 link1 -> dest
lrwxrwxrwx 1 username 11 Mar 26 20:21 link2 -> longer_dest
where link1 takes up 4 bytes, which is the length of dest; link2 takes up 11 bytes, which is the length of longer_dest. Therefore, symlinks are in fact no more than the destination path stored in plain text. So I am wondering if it is possible to edit (the destination) of a symlink in text editors, preferably Emacs. I googled for a while and couldn't find anyone talking about this. Note that this question is purely out of curiosity; I know full well that I can overwrite a symlink by ln -f -s.

Yes, in Emacs this is possible in dired-mode, specifically wdired (writable dired) mode.
Note, dired and wdired both are built-in packages.
Here's an example...
(BTW: I'm using Smex to give Emacs M-x command search & execute a more ergonomic UI + fuzzy matching)

It's possible in principle, but the editor would need to specifically support it, since reading the destination of a symlink requires a special system call: readlink().
You're unlikely to find any editors that actually do this, since it's not very useful, and conflicts with what most users want the editor to do when asked to open a symlink: open the file that it points to.

As per the Storage of symbolic links section in Wikipedia's article Symbolic Links, the symlinks are stored in an inode. This inode is a data structure containing several information about the file in question - as per this thread, the touch command can be used to change some of its values. So, it may not be possible to modify it by using a text editor, due to the problems that #Wyzard mentioned, but it might be modifiable by using some other command-line tools like touch.
I hope this helps!

It's not possible directly, as others have already pointed out, but of course you can write a script for it. Here's one I came up with when I had to change lots of symlinks
#! /bin/bash
tmp=$(mktemp)
trap "rm $tmp" EXIT
while [ ! -z "$1" ]; do
filename="$1"; shift
if [ ! -h "$filename" ]; then
echo "Not a symlink: $filename";
continue
fi
stat -c "%N" "$filename" >> $tmp
done
emacs $tmp
while read filename linkname; do
ln -sf "$linkname" "$filename"
done < <(sed "s/'\(.*\)' -> '\(.*\)'/\1 \2/" $tmp)
It worked for me, but it's certainly not perfect, so use at your own risk...

Related

Linux console equivalent to gui copy/paste file/directory scenario

How to simply recreate copy/paste functionality like in gui environments?
My typical scenario for copying file/directory in Linux console is:
cp source_path target_path
Sometimes paths are relative, sometimes absolute, but I need to provide them both. It works, but there are situations where I would like to recreate scenario from gui which is:
1. go to source directory
2. copy file/directory
3. go to target directory
4. paste file/directory
I imagine something like
cd source_directory_path
copy_to_stash source_name
cd target_directory_path
paste_from_stash [optional_new_target_name]
I know that there is a xclip app, but a documentation says that it copies content of a file, not a file handle. Also, I can use $OLDPWD variable and expand it when I copy file, but this is not a solution without some cumbersome.
Is there some simple, general, keyboard only, not awkward to use equivalent?
I've also asked the same question on superuser and answer that I've received is good enough for me.
In short: two additional scripts and temporary variable to hold intermediate value.
Below is a code and link to original answer.
#!/bin/bash
# source me with one of:
# source [file]
# . [file]
# Initialize
sa_file=
sa(){
# Fuction to save a file in the current PWD
if [[ -e "$PWD/$1" ]]; then
sa_file=$PWD/$1
echo "Saved for later: $sa_file"
else
echo "Error: file $PWD/$1 does not exist"
fi
}
pa(){
# Paste if file exists, to $1 if exists
if [[ -e "$sa_file" ]]; then
if [[ $1 ]]; then
cp -v "$sa_file" "$1"
else
cp -v "$sa_file" .
fi
else
echo "Error: file $sa_file does not exist, could not copy"
fi
}
https://superuser.com/a/1405953/614464
The way I see it your only option is to write a script to do all of those steps. You could easily implement the clipboard functionality by copying the file to the /tmp directory before copying again from it.
This should work as intended.
Usage: script [from] [to]
filename=$(basename "$0")
tmpfile=/tmp/$filename.$RANDOM
cd $(dirname "$0")
cp $tmpfile $filename
cd $(dirname "$1")
cp $tmpfile $(basename "$1")
One option: you can either copy-paste the filename using mouse, using copy-paste feature from your terminal emulator (e.g. Konsole or GNOME Terminal), but this: 1) requires a GUI since the terminal emulator software run in GUI; 2) well, requires a mouse.
Another option: utilize shell tab completion. You still need to type the filename, but not all of it.
Third option, and this is closer to how you work in a GUI file explorer: use a TUI-based file explorer, e.g. the dual-pane style Midnight Commander. You can use arrow keys (if you turn on the Lynx-like motion setting, which is very recommended) to quickly navigate the directory tree. Then select files using the Insert, +, -, or * keys, then copy/move files from one pane to another. It's very convenient. In fact half of the time I spend in CLI, I spend in MC.

Bash script: Recognizing paths drag-and-dropped to konsole

I was looking to make script that can copy user files within a Windows user directory to a backup drive. I pretty much want everything except Appdata to be transferred. I made a real simple script, but since the folders I am transferring to have spaces in the name (ex. '/media/gage/Backup\ Drive/'), it says that Drive' does not exist.
I am trying to drag&drop/paste the directory from a file manager onto the terminal and it ends up having 's around the entire path once I drag it over. Is there any way to have the input recognize the file names with the 's around it?
Here's what I have so far (I'm really new to bash scripts)
#!/bin/bash
echo "Enter the full path to the user's directory"
read srcName
echo "Enter the full path to the backup directory"
read dstName
echo "Copying from Users to Backup"
cd $srcName
cp -rp Documents $dstName
cp -rp Pictures $dstName
cp -rp Desktop $dstName
cp -rp Music $dstName
cp -rp Videos $dstName
cp -rp Downloads $dstName
cp -rp Favorites $dstName
Any help is appreciated
Thanks.
Terminals predate both drag&drop and copy&paste, so neither is integrated in a robust way. It's up to each terminal emulator to decide what to do.
Here's how some common ones react when you drag&drop one or more files from a graphical file manager:
xterm does nothing.
gnome-terminal pretends you typed the paths as space separated, shell escaped words, each of which is entirely single quoted with appropriate escapes:
'/path/foo' '/path/Rock Lobster - B-52'\''s.mp3'
konsole pops up a menu to let you choose between copy/move to the current directory of the shell, or to paste the paths as shell escaped words, which are only single quoted if they contain metacharaters:
/path/foo '/path/Rock Lobster - B-52'\''s.mp3'
From what you're describing, you're using gnome-terminal and just didn't try to drag&drop a file containing single quotes to see what else it does to the filename.
So what can you do?
I would recommend you just require that the path be copy-pasted verbatim, rather than drag&dropping files. This is how every other program works, and what you can do with Charles Duffy's solution.
To copy-paste the path as a string rather than dragging a file, you can usually open a Properties or Details tab in the file manager and copy the full path from there.
However, for fun, here's how you could interpret input as drag&dropped files from a file manager if you really wanted to, by populating an array using eval:
#!/bin/bash
echo "Drag&Drop files/dirs and press enter when done."
echo "Do not drag&drop/paste/type text, because it will be evaluated as code."
IFS="" read -r input
eval "files=( $input )"
echo "Here are the things you pasted:"
for file in "${files[#]}"
do
ls -ld "$file"
done
which runs like this:
$ ./test
Drag&Drop files/dirs and press enter when done.
Do not drag&drop/paste/type text, because it will be evaluated as code.
'/usr/local/home/me/Documents' '/usr/local/home/me/Downloads'
Here are the things you pasted:
drwxr-x--- 3 me eng 4096 Aug 7 13:46 /usr/local/home/me/Documents
drwxr-x--- 2 me eng 4096 Aug 17 14:32 /usr/local/home/me/Downloads

How to duplicate a folder exactly

I am trying to copy a filesystem for a device I am programming for. After so much time trying to figure out why the filesystem I was installing wasn't working I found out that cp didn't get the job done. I used du -s to check the size of the original filesystem and the one that I copied with cp -r, as it turns out they differ by about 150 bytes.
Something is telling me that symbolic links or some sort of kernel objects aren't being copied correctly.
Is it possible to copy a folder/file system exactly? If so how would I go about it?
Try doing this the straightforward way :
cp -a src target
from man cp
-a, --archive
same as -dR --preserve=all
It preserve rights, symlinks...
Here I tried all the code in my Linux. Seems Rsync proposed by #seanmcl as the right one while others failed to keep owners and/or some special files or a denied result. The exact code is:
$ sudo rsync -aczvAXHS --progress /var/www/html /var/www/backup
Just remember to use just the directory name and not put a slash (/) or a wildcard (/*) at the end of source and target name otherwise the hidden files right below the source are not copied.
Another popular option is to use tar c source | (cd target && tar x ). See this linuxdevcenter.com article.
The most accurate way I know of copying files is with cpio:
cd /path/to/source
find . -xdev -print0 | cpio -oa0V | (cd /path/to/target && cpio -imV)
Not really easy to use, but this is very precise, preserving timestamps, owners, permissions, special files.
Rsync is the best way to copy a file system. They are myriad arguments that let you control exactly what is copied.
This is what I do, for example to duplicate directory A -> B:
$ mkdir B
$ cd A
$ cp -a ./ ../B

How can I symlink a file in Linux? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 4 years ago.
Improve this question
I want to make a symbolic link in Linux. I have written this Bash command where the first path is the folder I want link into and the second path is the compiled source.
ln -s '+basebuild+'/IpDome-kernel/kernel /home/build/sandbox/gen2/basebuild/IpDome-kernel/kernal
Is this correct?
To create a new symlink (will fail if symlink exists already):
ln -s /path/to/file /path/to/symlink
To create or update a symlink:
ln -sf /path/to/file /path/to/symlink
ln -s TARGET LINK_NAME
Where the -s makes it symbolic.
ln -s EXISTING_FILE_OR_DIRECTORY SYMLINK_NAME
ln -s target linkName
You can have a look at the man page here:
http://linux.die.net/man/1/ln
(Because an ASCII picture is worth a thousand characters.)
An arrow may be a helpful mnemonic, especially since that's almost exactly how it looks in Emacs' dired.
And big picture so you don't get it confused with the Windows' version
Linux:
ln -s target <- linkName
Windows:
mklink linkName -> target
You could also look at these as
ln -s "to-here" <- "from-here"
mklink "from-here" -> "to-here"
The from-here should not exist yet, it is to be created, while the to-here should already exist (IIRC).
(I always get mixed up on whether various commands and arguments should involve a pre-existing location, or one to be made.)
EDIT: It's still sinking in slowly for me; I have another way I've written in my notes.
ln -s (target exists) (link is made)
mklink (link is made) (target exists)
ln -s source_file target_file
http://unixhelp.ed.ac.uk/CGI/man-cgi?ln
To the original question:
'ln -s '+basebuild+'/IpDome-kernel/kernel /home/build/sandbox/gen2/basebuild/IpDome-kernel/kernal'
This will indeed create a symbolic link (-s) from the file/directory:
<basebuild>/IpDome-kernel/kernel
to your new link
/home/build/sandbox/gen2/basebuild/IpDome-kernel/kernal
Here's a few ways to help you remember:
First, there's the man page for ln. You can access this via searching "man ln" in google, or just open a terminal window and type man ln and you'll get the same information. The man page clearly states:
ln [OPTION]... [-T] TARGET LINK_NAME (1st form)
If having to search or read through a man page every time isn't for you, maybe you'll have an easier time remembering that all nix commands work the same way:
cp /file/that/exists /location/for/new/file
mv /file/that/exists /location/its/moving/to
ln /file/that/exists /the/new/link
cp copies a file that currently exists (the first argument) to a new file (the second argument).
mv moves a file that currently exists (the first argument) to a new place (the second argument)
Likewise ln links a file that currently exists (the first argument) to a new link (the second argument)*
The final option I would like to suggest is you can create your own man pages that are easy to read and easy (for you) to find/remember. Just make a simple shell script that gives you the hint you need. For example♦:
In your .bash_aliases file you can place something like:
commandsfx() {
echo "Symlink: ln -s /path/to/file /path/to/symlink"
echo "Copy: cp /file/to/copy /destination/to/send/copy"
}
alias 'cmds'=commandsfx
Then when you need it, from the command line just type cmds and you'll get back the proper syntax in a way you can quickly read and understand it. You can make these functions as advanced as you'd like to get what what information you need, it's up to you. You could even make them interactive so you just have to follow the prompts.. something like:
makesymlink() {
echo "Symlink name:"
read sym
echo "File to link to:"
read fil
ln -s $fil $sym
}
alias 'symlink'=makesymlink
* - well obviously they can all take different parameters and do different things and can work on files as well as directories... but the premise is the same
♦ - examples using the bash shell
ln [-Ffhinsv] source_file [target_file]
link, ln -- make links
-s Create a symbolic link.
A symbolic link contains the name of the file to which it is linked.
An ln command appeared in Version 1 AT&T UNIX.
Creating Symbolic links or Soft-links on Linux:
Open Bash prompt and type the below mentioned command to make a symbolic link to your file:
A) Goto the folder where you want to create a soft link and typeout the command as mentioned below:
$ ln -s (path-to-file) (symbolic-link-to-file)
$ ln -s /home/user/file new-file
B) Goto your new-file name path and type:
$ ls -lrt (To see if the new-file is linked to the file or not)
Example:
user#user-DT:[~/Desktop/soft]# ln -s /home/user/Desktop/soft/File_B /home/user/Desktop/soft/File_C
user#user-DT:[~/Desktop/soft]# ls -lrt
total 0
-rw-rw-r-- 1 user user 0 Dec 27 16:51 File_B
-rw-rw-r-- 1 user user 0 Dec 27 16:51 File_A
lrwxrwxrwx 1 user user 31 Dec 27 16:53 File_C -> /home/user/Desktop/soft/File_B
Note: Where, File_C -> /home/user/Desktop/soft/File_B Means, File_C is symbolically linked to File_B
ln -s sourcepath linkpathname
Note:
-s makes symbolic links instead of hard links
This is Stack Overflow so I assume you want code:
All following code assumes that you want to create a symbolic link named /tmp/link that links to /tmp/realfile.
CAUTION: Although this code checks for errors, it does NOT check if /tmp/realfile actually exists ! This is because a dead link is still valid and depending on your code you might (rarely) want to create the link before the real file.
Shell (bash, zsh, ...)
#!/bin/sh
ln -s /tmp/realfile /tmp/link
Real simple, just like you would do it on the command line (which is the shell). All error handling is done by the shell interpreter. This code assumes that you have a working shell interpreter at /bin/sh .
If needed you could still implement your own error handling by using the $? variable which will only be set to 0 if the link was successfully created.
C and C++
#include <unistd.h>
#include <stdio.h>
int main () {
if( symlink("/tmp/realfile", "/tmp/link") != 0 )
perror("Can't create the symlink");
}
symlink only returns 0 when the link can be created. In other cases I'm using perror to tell more about the problem.
Perl
#!/usr/bin/perl
if( symlink("/tmp/realfile", "/tmp/link") != 1) {
print STDERR "Can't create the symlink: $!\n"
}
This code assumes you have a perl 5 interpreter at /usr/bin/perl. symlink only returns 1 if the link can be created. In other cases I'm printing the failure reason to the standard error output.
If you are in the directory where you want to create symlink, then ignore second path.
cd myfolder
ln -s target
It will create symlink of target inside myfolder.
General syntax
ln -s TARGET LINK_NAME
I'd like to present a plainer-English version of the descriptions already presented.
ln -s /path-text/of-symbolic-link /path/to/file-to-hold-that-text
The "ln" command creates a link-FILE, and the "-s" specifies that the type of link will be symbolic. An example of a symbolic-link file can be found in a WINE installation (using "ls -la" to show one line of the directory contents):
lrwxrwxrwx 1 me power 11 Jan 1 00:01 a: -> /mnt/floppy
Standard file-info stuff is at left (although note the first character is an "l" for "link"); the file-name is "a:" and the "->" also indicates the file is a link. It basically tells WINE how Windows "Drive A:" is to be associated with a floppy drive in Linux. To actually create a symbolic link SIMILAR to that (in current directory, and to actually do this for WINE is more complicated; use the "winecfg" utility):
ln -s /mnt/floppy a: //will not work if file a: already exists
To create a symbolic link /soft link, use:
ln -s {source-filename} {symbolic-filename}
e.g.:
ln -s file1 link1
Links are basically of two types:
Symbolic links (soft): link to a symbolic path indicating the abstract location of another file
Hard links: link to the specific location of physical data.
Example 1:
ln /root/file1 /root/file2
The above is an example of a hard link where you can have a copy of your physical data.
Example 2:
ln -s /path/to/file1.txt /path/to/file2.txt
The above command will create a symbolic link to file1.txt.
If you delete a source file then you won't have anything to the destination in soft.
When you do:
ls -lai
You'll see that there is a different inode number for the symlinks.
For more details, you can read the man page of ln on your Linux OS.
There are two types of links:
symbolic links: Refer to a symbolic path indicating the abstract location of another file
hard links: Refer to the specific location of physical data.
In your case symlinks:
ln -s source target
you can refer to http://man7.org/linux/man-pages/man7/symlink.7.html
you can create too hard links
A hard link to a file is indistinguishable from the original directory entry; any changes to a file are effectively independent of the name used to reference the file. Hard links may not normally refer to directories and may not span file systems.
ln source link
I find a bit confusing the terminologies "target" and "directory" in the man information.
The target is the folder that we are symlinking to and the directory the actual symlink (not the directory that you will be symlinking to), if anyone is experiencing the same confusion, don't feel alone.
This is my interpretation of creating a Symlink (in linux):
ln -s /FULL/PATH/FOLDER-OR-FILE-SYMLINKING-TO NAME-OF-YOUR-SYMLINK
You can navigate to the folder where you want to create the symlink and run the command or specify the FULL PATH for your symlink instead of NAME-OF-YOUR-SYMLINK.
cd /FULL/PATH/TO/MY-SYMLINK-PARENT-FOLDER
ln -s /FULL/PATH/FOLDER-OR-FILE-SYMLINKING-TO NAME-OF-YOUR-SYMLINK
OR
ln -s /FULL/PATH/FOLDER-OR-FILE-SYMLINKING-TO /FULL/PATH/TO/MY-SYMLINK-PARENT-FOLDER/NAME-OF-YOUR-SYMLINK
I hope this helps to those (still) slighly confused.
How to create symlink in vagrant.
Steps:
In vagrant file create a synced folder. e.g config.vm.synced_folder "F:/Sunburst/source/sunburst/lms", "/source"
F:/Sunburst/source/sunburst/lms :- where the source code, /source :- directory path inside the vagrant
Vagrant up and type vagrant ssh and go to source directory e.g cd source
Verify your source code folder structure is available in the source directory. e.g /source/local
Then go to the guest machine directory where the files which are associate with the browser. After get backup of the file. e.g sudo mv local local_bk
Then create symlink e.g sudo ln -s /source/local local. local mean link-name (folder name in guest machine which you are going to link)
if you need to remove the symlink :- Type sudo rm local

Need to monitor directory change, and perform action

1st of all: I'm not programmer, neither Linux guru, just have to work with Linux, Oracle, shell scripts.
My current task is to monitor a table in Oracle (tool: sqlplus), and if it contains a certain row, then watch a linux directory for a growing tmp file, and log its attributes (e.g. ls -l), in every 5 second.
The most important part is: this tmp file will be deleted if the above record is deleted from the oracle table, and I need the last contents of this tmp file.
I can't control the Oracle data, just got query rights.
The available tools are: bash, awk, sed, some old version of perl, ruby (not 1.9*), and python (2.5). I don't have install rights, so most of the outside libraries are not accessible. I know I can run some libraries from my $HOME, but I don't have internet connection on that machine: so can't download any library.
Inotify is not available (older kernel).
Any idea where to start/how to do it? Thanks in advance.
How about creating a hard link in another directory, then, when the file "disappears" in the original location, the hard link will still have access to the content.
This is ugly and naive... but...
#!/bin/bash
WASTHERE=0
MONITORING=/tmp/whatever.dat
LASTBACKUP=/tmp/mybackup.dat
LOGFILE=/tmp/mylog.log
# Just create an empty file to start with
touch "$LASTBACKUP"
while [ 1 ];
do
if [[ ! -e "$MONITORING" ]]; then
if [[ $WASTHERE -ne 0 ]]; then
echo "File is gone! Do something with $LASTBACKUP";
WASTHERE=0
fi
else
WASTHERE=1
ls -l "$MONITORING" >> $LOGFILE
cp "$MONITORING" "$LASTBACKUP"
fi
sleep 5
done
The unfortunate part about this is that if anything happens to the file being 'monitored' while the script is sleeping (content is written to it, for example) and the file is then deleted before the script wakes up, the newly written content will not be in the 'backup.'

Resources