I'm trying to figure out how to add content/code to the end of a .js file that already has code in it using ssh command.
ie....
touch ./ap/includes/ckeditor/ckeditor.js
Maintain current code
echo "add custom end code only"> ./ap/includes/ckeditor/ckeditor.js
sshcommand is used to connect to another server.
What you can do append text to the end of a file is to echo "something" >> /your/file.
So based on your code:
touch ./ap/includes/ckeditor/ckeditor.js
Maintain current code
echo "add custom end code only" >> ./ap/includes/ckeditor/ckeditor.js
^
|_ changed this
By the way, the touch part is unnecessary. When echoing inside the file, the date of the file will be updated. And if file does not exist, it will be automatically created with echo.
Related
References
Fullcode of what will be discussed here:
https://github.com/djon2003/com.cyberinternauts.linux.backup
activateLogs question that solved how to log to file and screen: https://stackoverflow.com/a/70792273/214898
Limitation
Just a small reminder from the last question: this script is executed on limited environment, on a QNAP (NAS).
Background
I have a function that activate logging which now has three modes: SCREEN, DISK, BOTH. With some help (from the question of the link above), I achieve to make work the BOTH option. DISK & BOTH use a file descriptor numbered 3. The first is pointing to a file and the second to stdout.
On exit of my script (using trap), it detects if there were logged errors and send them via email.
Code
function sendErrorMailOnExit()
{
## If errors happened, then send email
local isFileDescriptor3Exist=$(command 2>/dev/null >&3 && echo "Y")
if [ "$isFileDescriptor3Exist" = "Y" ]; then
local logFile=$(readlink /proc/self/fd/3 | sed s/.log$/.err/)
local logFileSize=$(stat -c %s "$logFile")
if [ $logFileSize -gt 0 ]; then
addLog "N" "Sending error email"
local logFileName=$(basename "$logFile")
local logFileContent=$(cat "$logFile")
sendMail "Y" "QNAP - Backup error" "Error happened on backup. See log file $logFileName\n\nLog error file content:\n$logFileContent"
fi
fi
}
trap sendErrorMailOnExit EXIT
Problem
As you can see, this works well because the file descriptor #3 is using a file. But now, using the BOTH option, the file descriptor #3 is pointing to stdout and the file is written via tee. Hence my question, how could I get the location of the file of tee.
Why not only using a variable coming from my function activateLogs would you say? Because, this function relaunches the script to be able to get all the logs not caught before the function is called. Thus why using this method to retrieve the error file location.
Possible solutions, but not the best (I hope)
One way would be to pass the file location through a script
parameter, but I would prefer not do that if that can be avoid.
Another, would be to create a "fake" file descriptor #4 (probably my best solution up to now) that would always point to the file.
Does anyone have an idea?
I finally opted for the creation of a "fake" file descriptor #4 that does not nothing except pointing to the current log file.
I tried to make a custom command that unzip a selected file to a path defined by user, but with a default value to current path and current archive name in remote server using this command, but the prompt just gave me an empty value. What's the mistake?
unzip "!" -d "!?&Extraction Path:?!/!!"
Thanks in advance!
It's not possible. There's actually a feature request for this functionality:
Bug 743 – Allow patterns in default prompt answer in custom commands.
Though even that it meant to support only static (non-file) patterns like !/, but not file patterns like !.
If it helps, in WinSCP extensions, it's possible to use non-file patterns, like !/ (but not file patterns, like !) in default prompt/option answer.
The extension file may look like:
#name Unzip...
#side Remote
#command unzip "!" -d "%ExtractionPath%"
#option ExtractionPath -run textbox "Extraction path:" "!/"
Just store the above script to a text file and install it to WinSCP.
Another thing that you can do, is to add a checkbox that will make WinSCP add an archive name (without an extension) to the path, with some clever use of shell (bash) constructs. This way, you can uncheck the checkbox and add a custom subfolder to the target path manually, if you do not want to use the archive name for the subfolder name.
#name Unzip...
#side Remote
#command unzip "!" -d "%ExtractionPath%`[[ '%AddName%' = '1' ]] && AN=! && echo ${AN%.*}`"
#option ExtractionPath -run textbox "Extraction path:" "!/"
#option AddName -run checkbox "Add file name to the extraction path" "1" "1"
Yet another alternative is to use your own placeholder for archive name (e.g. ARCHIVENAME) that will get replaced by real name (without an extension), when the command is executed. Then, if you do not want to use the archive name for the subfolder name, you replace the ARCHIVENAME with a custom name.
#name Unzip...
#side Remote
#command unzip "!" -d "`EP=%ExtractionPath%;AN=!;AN=${AN%.*};echo ${EP/ARCHIVENAME/$AN}`"
#option ExtractionPath -run textbox "Extraction path:" "!/ARCHIVENAME"
Usually I get an excel spreadsheet with dozens of filenames, for which I then need to go and search individually.
Spreadhseet
Is there a way that I could simply:
Select All filenames in e.g. row A of Excel,
then Search for all these files on "This Mac"
then Copy all found files into the New Folder on the Desktop
So far I've tried the first part of searching and this is what i get :a)
Automator with Variable. But the problem is, it only searches for 1 file from selection
b)
Automator with Shell Script (Copy to Clipboard > Open Finder > CMD+F (to highlight Search dialog) > CMD+V). It opens a new Finder window, but it doesn't paste the clipboard into search dialog
c) /usr/bin/pbcopy
on run {input, parameters}
tell application "System Events"
keystroke "f" using {command down}
keystroke "v" using {command down}
end tell
return input
end run`
End result, is same as option b). I was planning to run this in Automator as a 'Service', which I could later assign to Keyboard Shortcut.
I am pretty sure there should be a simple shell option for this - any advice would be much appreciated.
I made a bash script that does what you want. You would basically select a bunch of filenames in Excel, or any other app, and copy them to the clipboard with ⌘C. After that you need to run the script and it will take items from the clipboard and search for TIFF or JPEG images that match that name and copy them to a directory on your Desktop called Selected Files:
#!/bin/bash
# Get contents of clipboard into bash array
files=( $(pbpaste) )
# Create output directory - no checks for already existing or already containing files
OUTDIR="$HOME/Desktop/Selected Files"
mkdir -p "$OUTDIR"
# Iterate through fetching files
for ((i=0;i<${#files[#]};i++)) ; do
name=${files[i]}
result=$( mdfind "kMDItemDisplayName == \"${name}.*\" && (kMDItemKind==\"TIFF image\" || kMDItemKind==\"JPEG image\")" )
if [ -f "$result" ]; then
echo $name: $result
cp "$result" "$OUTDIR"
else
echo ERROR: Searched for: $name, found $result
fi
done
I am not sure of your level of familiarity with bash, so you may be able to ignore the following...
Make a new directory for your own scripts:
mkdir -p $HOME/scripts
Save the above script in that directory with filename:
$HOME/scripts/gather
Make the script executable by typing this into Terminal:
chmod +x $HOME/scripts/gather
Edit your login profile ($HOME/.profile) and add your $HOME/scripts directory to your PATH:
export PATH="$PATH":$HOME/scripts
Then start a new Terminal and you can use any script that you have saved in $HOME/scripts without needing to specify the full path to it, e.g.:
gather
Following information kindly contributed by #user3439894 in comments section, as I am out of my depth on this aspect...
To use a keyboard shortcut, you'd have to create an Automator "Service workflow" with a "Run Shell Script" action, which you can assign a keyboard shortcut to under: System Preferences > Keyboard > Shortcuts > Services
I'm trying to redirect(?) my standard error/output to a text file.
I did my research, but for some reason the online answers are not working for me.
What am I doing wrong?
cd /home/user1/lists/
for dir in $(ls)
do
(
echo | $dir > /root/user1/$dir" "log.txt
) > /root/Desktop/Logs/Update.log
done
I also tried
2> /root/Desktop/Logs/Update.log
1> /root/Desktop/Logs/Update.log
&> /root/Desktop/Logs/Update.log
None of these work for me :(
Help please!
Try this for the basics:
echo hello >> log.txt 2>&1
Could be read as: echo the word hello, redirecting and appending STDOUT to the file log.txt. STDERR (file descriptor 2) is redirected to wherever STDOUT is being pointed. Note that STDOUT is the default and thus there is no "1" in front of the ">>". Works on the current line only.
To redirect and append all output and error of all commands in a script, put this line near the top. It will be in effect for the length of the script instead of doing it on each line:
exec >>log.txt 2>&1
If you are trying to obtain a list of the files in /home/user1/lists, you do not need a loop at all:
ls /home/usr1/lists/ >Update.log
If you are attempting to run every file in the directory as an executable with a newline as its input, and collect the output from all these programs in Update.log, try this:
for file in /home/user1/lists/*; do
echo | "$file"
done >Update.log
(Notice how we avoid the useless use of ls and how there is no redirection inside the loop.)
If you want to create an empty file called *.log.txt for each file in the directory, you would do
for file in /home/user1/lists/*; do
touch "$(basename "$file")"log.txt
done
(Using basename to obtain the file name without the directory part avoids the cd but you could do it the other way around. Generally, we tend to avoid changing the directory in scripts, so that the tool can be run from anywhere and generate output in the current directory.)
If you want to create a file containing a single newline, regardless of whether it already exists or not,
for file in /home/user1/lists/*; do
echo >"$(basename "$file")"log.txt
done
In your original program, you redirect the echo inside the loop, which means that the redirection after done will not receive any output at all, so the created file will be empty.
These are somewhat wild guesses at what you might actually be trying to accomplish, but should hopefully help nudge you slightly in the right direction. (This should properly be a comment, I suppose, but it's way too long and complex.)
I am new to shell scripting in Linux and I am trying to take data from the keyboard and then append the data passed in to a file. Pretty straight forward but I am getting an error when I try to create the file. The error says "you do not have permission to create this file".
I first do a check to make sure the file exists. If it exists, append to the end of the file. If not, create the file. What am I doing wrong?
Thank you!
P.S. In this case, I do not have the file created yet
#!/bin/sh
echo "Please enter your first name";
read first
echo "Please enter your last name";
read last
combine=":$first $last"
file="/testFile.dat"
if [ -f "$file" ]
then
echo "$file found."
echo $combine >> $file
else
echo "$file not found. Will create the file and add entry now."
touch $file
$combine >> $file
fi
You're trying to write to the file /testFile.dat which is located in the root directory /. It is highly likely that as a regular user you would not have write permissions for creating such a file.
But what you wanted I'm guessing is to create the testfile.dat in the current directory.
Replace the following line:
file="/testFile.dat"
with:
file="./testFile.dat"
You are creating the file at the root. Try file="~/testFile.dat" to create the file in your home or just file="./testFile.dat" to create it in the current directory.